From 34255f82b8d2a07170f33bca9bcecaf4fd9813fc Mon Sep 17 00:00:00 2001 From: InsanityAutomation <38436470+InsanityAutomation@users.noreply.github.com> Date: Sun, 30 Sep 2018 15:25:02 -0400 Subject: [PATCH] Bump to head, add new filament sensor type --- Marlin/Conditionals_LCD.h | 10 + Marlin/Conditionals_post.h | 91 ++- Marlin/Configuration.h | 10 +- Marlin/G26_Mesh_Validation_Tool.cpp | 12 +- Marlin/HAL.h | 2 - Marlin/Makefile | 5 +- Marlin/Marlin.h | 97 ++- Marlin/Marlin.ino | 2 +- Marlin/MarlinConfig.h | 2 +- Marlin/Marlin_main.cpp | 1162 ++++++++++++++++++++------- Marlin/Max7219_Debug_LEDs.cpp | 529 ++++++------ Marlin/Max7219_Debug_LEDs.h | 159 ++-- Marlin/SanityCheck.h | 137 +++- Marlin/Sd2Card.cpp | 2 +- Marlin/Version.h | 6 +- Marlin/configuration_store.cpp | 210 ++++- Marlin/drivers.h | 62 +- Marlin/endstops.cpp | 55 +- Marlin/endstops.h | 10 +- Marlin/enum.h | 20 +- Marlin/fwretract.cpp | 12 +- Marlin/language.h | 28 +- Marlin/language_an.h | 1 + Marlin/language_bg.h | 1 + Marlin/language_ca.h | 1 + Marlin/language_cn.h | 1 + Marlin/language_cz.h | 1 + Marlin/language_cz_utf8.h | 9 + Marlin/language_da.h | 1 + Marlin/language_de.h | 1 + Marlin/language_el-gr.h | 1 + Marlin/language_el.h | 1 + Marlin/language_en.h | 8 +- Marlin/language_es.h | 1 + Marlin/language_es_utf8.h | 1 + Marlin/language_eu.h | 1 + Marlin/language_fi.h | 1 + Marlin/language_fr.h | 5 +- Marlin/language_fr_utf8.h | 19 +- Marlin/language_gl.h | 2 +- Marlin/language_hr.h | 1 + Marlin/language_it.h | 1 + Marlin/language_kana.h | 1 + Marlin/language_kana_utf8.h | 1 + Marlin/language_nl.h | 1 + Marlin/language_pl-DOGM.h | 1 + Marlin/language_pl-HD44780.h | 1 + Marlin/language_pt-br.h | 1 + Marlin/language_pt-br_utf8.h | 1 + Marlin/language_pt.h | 1 + Marlin/language_pt_utf8.h | 1 + Marlin/language_ru.h | 1 + Marlin/language_sk_utf8.h | 1 + Marlin/language_tr.h | 1 + Marlin/language_uk.h | 1 + Marlin/language_zh_CN.h | 1 + Marlin/language_zh_TW.h | 1 + Marlin/macros.h | 17 +- Marlin/nozzle.cpp | 8 +- Marlin/pca9632.cpp | 2 +- Marlin/pins.h | 69 +- Marlin/pinsDebug_list.h | 12 + Marlin/pins_ANET_10.h | 4 +- Marlin/pins_EINSY_RAMBO.h | 5 +- Marlin/pins_RIGIDBOARD.h | 1 + Marlin/pins_TRIGORILLA_14.h | 49 +- Marlin/pins_ULTIMAKER.h | 2 +- Marlin/planner.cpp | 337 ++++++-- Marlin/planner.h | 113 ++- Marlin/planner_bezier.cpp | 38 +- Marlin/power.cpp | 26 +- Marlin/power_loss_recovery.cpp | 2 +- Marlin/status_screen_lite_ST7920.h | 38 +- Marlin/stepper.cpp | 184 +++-- Marlin/stepper.h | 28 +- Marlin/stepper_indirection.cpp | 72 +- Marlin/temperature.cpp | 30 +- Marlin/thermistortable_501.h | 4 +- Marlin/thermistortable_71.h | 82 +- Marlin/twibus.cpp | 6 +- Marlin/twibus.h | 13 +- Marlin/ubl.cpp | 4 +- Marlin/ubl_G29.cpp | 6 +- Marlin/ubl_motion.cpp | 45 +- Marlin/ultralcd.cpp | 23 +- Marlin/ultralcd_impl_DOGM.h | 8 +- 86 files changed, 2718 insertions(+), 1206 deletions(-) diff --git a/Marlin/Conditionals_LCD.h b/Marlin/Conditionals_LCD.h index a796e24667..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 diff --git a/Marlin/Conditionals_post.h b/Marlin/Conditionals_post.h index 26b2437178..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) @@ -409,17 +421,17 @@ #if HAS_DRIVER(TB6560) #define MINIMUM_STEPPER_DIR_DELAY 15000 #elif HAS_DRIVER(TB6600) - #define MINIMUM_STEPPER_DIR_DELAY 1500 + #define MINIMUM_STEPPER_DIR_DELAY 1500 #elif HAS_DRIVER(DRV8825) - #define MINIMUM_STEPPER_DIR_DELAY 650 + #define MINIMUM_STEPPER_DIR_DELAY 650 #elif HAS_DRIVER(LV8729) - #define MINIMUM_STEPPER_DIR_DELAY 500 + #define MINIMUM_STEPPER_DIR_DELAY 500 #elif HAS_DRIVER(A4988) - #define MINIMUM_STEPPER_DIR_DELAY 200 - #elif HAS_TRINAMIC || HAS_DRIVER(TMC2130_STANDALONE) || HAS_DRIVER(TMC2208_STANDALONE) || HAS_DRIVER(TMC26X_STANDALONE) || HAS_DRIVER(TMC2660_STANDALONE) - #define MINIMUM_STEPPER_DIR_DELAY 20 + #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 0 // Expect at least 10µS since one Stepper ISR must transpire + #define MINIMUM_STEPPER_DIR_DELAY 200 // Expect at least 10µS since one Stepper ISR must transpire #endif #endif @@ -427,33 +439,33 @@ #if HAS_DRIVER(TB6560) #define MINIMUM_STEPPER_PULSE 30 #elif HAS_DRIVER(TB6600) - #define MINIMUM_STEPPER_PULSE 3 + #define MINIMUM_STEPPER_PULSE 3 #elif HAS_DRIVER(DRV8825) - #define MINIMUM_STEPPER_PULSE 2 + #define MINIMUM_STEPPER_PULSE 2 #elif HAS_DRIVER(A4988) || HAS_DRIVER(LV8729) - #define MINIMUM_STEPPER_PULSE 1 - #elif HAS_TRINAMIC || HAS_DRIVER(TMC2130_STANDALONE) || HAS_DRIVER(TMC2208_STANDALONE) || HAS_DRIVER(TMC26X_STANDALONE) || HAS_DRIVER(TMC2660_STANDALONE) - #define MINIMUM_STEPPER_PULSE 0 + #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 2 + #define MINIMUM_STEPPER_PULSE 1 #endif #endif #ifndef MAXIMUM_STEPPER_RATE #if HAS_DRIVER(TB6560) - #define MAXIMUM_STEPPER_RATE 15000 + #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(TMC2130_STANDALONE) || HAS_DRIVER(TMC2208_STANDALONE) || HAS_DRIVER(TMC26X_STANDALONE) || HAS_DRIVER(TMC2660_STANDALONE) + #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 250000 + #define MAXIMUM_STEPPER_RATE 500000 #endif #endif @@ -717,11 +729,33 @@ #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_STEALTHCHOP (HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2208)) -#define HAS_STALLGUARD (HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2660)) +#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) || AXIS_DRIVER_TYPE(ST, TMC2660) ) +#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 @@ -1367,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 39e77872f2..171adcedc4 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -31,6 +31,8 @@ * Enables a filament sensor plugged into the laser pin. Disables the laser */ //#define FilamentSensor +//#define ledgeFilSensor //Modify filament sensor contact type for TM3D V2 sensors + /** * Configuration.h * @@ -900,7 +902,11 @@ #endif #if ENABLED(FILAMENT_RUNOUT_SENSOR) #define NUM_RUNOUT_SENSORS 1 // Number of sensors, up to one per extruder. Define a FIL_RUNOUT#_PIN for each. - #define FIL_RUNOUT_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 FIL_RUNOUT_PIN 4 #define FILAMENT_RUNOUT_SCRIPT "M600" @@ -1078,7 +1084,7 @@ #endif // Add a menu item to move between bed corners for manual bed adjustment -//#define LEVEL_BED_CORNERS +#define LEVEL_BED_CORNERS #if ENABLED(LEVEL_BED_CORNERS) #define LEVEL_CORNERS_INSET 30 // (mm) An inset for corner leveling 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 e9dd09c175..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) 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 ef1a0cc9ee..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 @@ -301,12 +340,16 @@ extern float soft_endstop_min[XYZ], soft_endstop_max[XYZ]; void tool_change(const uint8_t tmp_extruder, const float fr_mm_s=0.0, bool no_move=false); -void home_all_axes(); +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 @@ -339,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 @@ -503,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 5b049a387f..e1988fe637 100644 --- a/Marlin/MarlinConfig.h +++ b/Marlin/MarlinConfig.h @@ -25,10 +25,10 @@ #include "boards.h" #include "macros.h" -#include "drivers.h" #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 707315d055..b6c7e0511e 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,6 +133,7 @@ * 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. @@ -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) @@ -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) @@ -769,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() { @@ -798,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; } } @@ -1039,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; @@ -1329,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) @@ -1553,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 } /** @@ -1563,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 @@ -1582,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); @@ -2481,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) @@ -2618,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 @@ -2630,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 @@ -2678,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(']'); } @@ -2985,11 +3027,16 @@ 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(); @@ -3229,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; } } @@ -3242,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 @@ -3283,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]; @@ -3294,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 @@ -3362,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) } @@ -3553,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) /** @@ -3965,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() { @@ -4143,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'), @@ -4831,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) @@ -5671,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); @@ -6055,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 @@ -6147,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); @@ -6158,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); @@ -6183,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(); @@ -6359,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; @@ -6368,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 @@ -6401,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 /** @@ -6612,7 +6934,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(); @@ -7063,7 +7385,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); @@ -7073,7 +7395,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(); @@ -7325,6 +7647,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; @@ -7333,7 +7656,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); @@ -7828,7 +8151,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) { @@ -8115,8 +8438,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); @@ -8149,12 +8473,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 @@ -8633,12 +8958,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 @@ -8688,20 +9013,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 @@ -8711,6 +9036,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); } } @@ -8722,14 +9052,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(); @@ -8794,9 +9128,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)); } @@ -8820,7 +9154,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); @@ -8833,13 +9167,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(); } @@ -9135,8 +9475,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); } @@ -9163,8 +9503,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); } @@ -9205,7 +9545,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) @@ -9215,7 +9555,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) @@ -9231,15 +9571,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 } @@ -9358,6 +9705,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) /** @@ -10775,7 +11158,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); } @@ -10921,7 +11304,7 @@ 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 @@ -10930,45 +11313,52 @@ inline void gcode_M502() { * X - X position of an LED to set or toggle * Y - Y position of an LED to set or toggle * V - The potentially 32-bit value or on/off state to set - * (for example: a chain of 4 Max7219 devices can have 32 bit + * (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(); + if (parser.seen('I')) { + max7219.register_setup(); + max7219.clear(); + } - if (parser.seen('F')) - for(uint8_t x = 0; x < MAX7219_X_LEDS; x++) - Max7219_Set_Column(x, 0xffffffff); + if (parser.seen('F')) max7219.fill(); + + const uint32_t v = parser.ulongval('V'); if (parser.seenval('R')) { - const uint32_t r = parser.value_int(); - Max7219_Set_Row(r, parser.ulongval('V')); - return; + const uint8_t r = parser.value_byte(); + max7219.set_row(r, v); } else if (parser.seenval('C')) { - const uint32_t c = parser.value_int(); - Max7219_Set_Column(c, parser.ulongval('V')); - return; + const uint8_t c = parser.value_byte(); + max7219.set_column(c, v); } - - if (parser.seenval('X') || parser.seenval('Y')) { + 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 x = 0; x < (8*MAX7219_NUMBER_UNITS); x++) { - SERIAL_ECHOPAIR("LEDs[", x); - SERIAL_ECHOPAIR("]=", LEDs[x]); - SERIAL_ECHO("\n"); + 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(); } - return; } - } #endif // MAX7219_GCODE @@ -11007,6 +11397,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() { @@ -11015,9 +11406,11 @@ 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 AXIS_IS_TMC(X) if (index < 2) TMC_SET_CURRENT(X); @@ -11048,20 +11441,52 @@ inline void gcode_M502() { #if AXIS_IS_TMC(E0) case 0: TMC_SET_CURRENT(E0); break; #endif - #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; + #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 } } @@ -11087,17 +11512,33 @@ inline void gcode_M502() { #if AXIS_IS_TMC(E0) TMC_SAY_CURRENT(E0); #endif - #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); + #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 AXIS_IS_TMC(E2) && EXTRUDERS == 2 + TMC_SAY_CURRENT(E2); + #endif + #if AXIS_IS_TMC(E3) && EXTRUDERS == 3 + TMC_SAY_CURRENT(E3); + #endif + #if AXIS_IS_TMC(E4) && EXTRUDERS == 4 + TMC_SAY_CURRENT(E4); + #endif + #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 } } @@ -11161,7 +11602,7 @@ 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) @@ -11194,6 +11635,7 @@ inline void gcode_M502() { #endif #endif + // 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_E(0) @@ -11253,7 +11695,7 @@ inline void gcode_M502() { 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 AXIS_HAS_STEALTHCHOP(E0) @@ -11603,7 +12045,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 @@ -11617,44 +12059,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 @@ -11662,7 +12099,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 @@ -11829,7 +12265,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 ); @@ -11900,7 +12336,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) { @@ -12016,6 +12452,12 @@ inline void invalid_extruder_error(const uint8_t e) { 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); @@ -12039,24 +12481,27 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n #endif } - - #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) - // Save current position to destination, for use later - if(current_position[X_AXIS] != x_home_pos(active_extruder)) - set_destination_from_current(); - else + + #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 + set_destination_from_current(); - #if ENABLED(PARKING_EXTRUDER) // Dual Parking extruder + + #if ENABLED(PARKING_EXTRUDER) parking_extruder_tool_change(tmp_extruder, no_move); #endif @@ -12093,11 +12538,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(); @@ -12141,6 +12581,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); @@ -12167,8 +12611,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 } @@ -12238,6 +12687,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 @@ -12300,6 +12753,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 @@ -12319,9 +12776,10 @@ void process_parsed_command() { case 4: gcode_M3_M4(false); break; // M4: Laser/CCW-Spindle Power case 5: gcode_M5(); break; // M5: Laser/Spindle OFF #endif + #if ENABLED(FAN_AS_LASER) - case 3: gcode_M3_M4(true); break; // M3: Laser Power On - case 5: gcode_M5(); break; // M5: Laser OFF + case 3: gcode_M3_M4(true); break; // M3: Laser Power On + case 5: gcode_M5(); break; // M5: Laser OFF #endif case 17: gcode_M17(); break; // M17: Enable all steppers @@ -12384,6 +12842,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) @@ -12597,8 +13057,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 @@ -13049,6 +13509,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. @@ -13065,6 +13634,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( @@ -13124,7 +13700,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 @@ -13199,6 +13775,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); @@ -13230,7 +13807,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); @@ -13267,6 +13844,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); @@ -13298,7 +13876,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); @@ -13329,10 +13907,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. @@ -13343,10 +13921,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 } @@ -13355,8 +13941,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 @@ -13450,6 +14039,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 @@ -13459,7 +14050,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); @@ -13472,7 +14063,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); @@ -13482,8 +14073,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 } @@ -13497,7 +14091,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); @@ -13509,7 +14103,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); @@ -13580,7 +14174,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) @@ -13597,7 +14191,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; @@ -13617,10 +14211,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(); @@ -13647,7 +14241,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. @@ -13658,17 +14252,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); } @@ -13737,7 +14331,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); @@ -13793,7 +14387,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); @@ -13850,7 +14444,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); @@ -13862,19 +14456,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)) @@ -13891,15 +14485,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 @@ -13926,26 +14520,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 } @@ -14078,14 +14680,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) { @@ -14259,10 +14868,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(); @@ -14328,7 +14937,7 @@ void idle( #endif ) { #if ENABLED(MAX7219_DEBUG) - Max7219_idle_tasks(); + max7219.idle_tasks(); #endif lcd_update(); @@ -14452,7 +15061,7 @@ void stop() { void setup() { #if ENABLED(MAX7219_DEBUG) - Max7219_init(); + max7219.init(); #endif #if ENABLED(DISABLE_JTAG) @@ -14510,7 +15119,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; @@ -14684,6 +15293,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 } /** diff --git a/Marlin/Max7219_Debug_LEDs.cpp b/Marlin/Max7219_Debug_LEDs.cpp index ff71903f24..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,12 +48,92 @@ #include "Marlin.h" #include "delay.h" -uint8_t LEDs[8*MAX7219_NUMBER_UNITS] = { 0 }; +Max7219 max7219; -// Delay for 0.1875µs (16MHz AVR) or 0.15µs (20MHz AVR) -#define SIG_DELAY() DELAY_NS(188) +uint8_t Max7219::led_line[MAX7219_LINES]; // = { 0 }; -void Max7219_PutByte(uint8_t data) { +#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 + #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 + +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 +} + +/** + * 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(); @@ -68,7 +148,7 @@ void Max7219_PutByte(uint8_t data) { CRITICAL_SECTION_END; } -void Max7219_pulse_load() { +void Max7219::pulse_load() { SIG_DELAY(); WRITE(MAX7219_LOAD_PIN, LOW); // tell the chip to load the data SIG_DELAY(); @@ -76,20 +156,39 @@ void Max7219_pulse_load() { SIG_DELAY(); } -void Max7219(const uint8_t reg, const uint8_t data) { +void Max7219::send(const uint8_t reg, const uint8_t data) { SIG_DELAY(); CRITICAL_SECTION_START; SIG_DELAY(); - Max7219_PutByte(reg); // specify register + putbyte(reg); // specify register SIG_DELAY(); - Max7219_PutByte(data); // put data + 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; @@ -98,11 +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) ); - Max7219_pulse_load(); // tell the chips to load the clocked out data + pulse_load(); // tell the chips to load the clocked out data value /= 10; if (!value && !leadzero) blank = true; dec = false; @@ -110,247 +209,197 @@ 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(); +// 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 > 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); + refresh_line(LED_IND(x, y)); +} + +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 > 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 > MAX7219_X_LEDS - 1 || y > MAX7219_Y_LEDS - 1) return error(PSTR("led_toggle"), x, y); + led_set(x, y, !BIT_7219(x, y)); +} + +void Max7219::send_row(const uint8_t row) { + #if _ROT == 0 || _ROT == 180 + refresh_line(LED_IND(0, row)); #else - UNUSED(func); UNUSED(v1); UNUSED(v2); + UNUSED(row); + refresh(); #endif } +void Max7219::send_column(const uint8_t col) { + #if _ROT == 90 || _ROT == 270 + refresh_line(LED_IND(col, 0)); + #else + UNUSED(col); + refresh(); + #endif +} + +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); +} + /** - * uint32_t flipped(const uint32_t bits, const uint8_t n_bytes) operates on the number - * of bytes specified in n_bytes. The lower order bits of the supplied bits are flipped. - * 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. + * 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°). */ - -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 = (outbits << 1); - if (bits & mask) - outbits |= 1; - mask <<= 1; +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; } - return outbits; + send_row(row); } -// 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 > (MAX7219_X_LEDS - 1) || y > (MAX7219_Y_LEDS - 1)) return Max7219_Error(PSTR("Max7219_LED_Set"), x, y); - if (BIT_7219(x, y) == on) return; - XOR_7219(x, y); - SEND_7219(MAX7219_UPDATE_AXIS); -} - -void Max7219_LED_On(const uint8_t x, const uint8_t y) { - if (x > (MAX7219_X_LEDS - 1) || y > (MAX7219_Y_LEDS - 1)) return Max7219_Error(PSTR("Max7219_LED_On"), x, y); - Max7219_LED_Set(x, y, true); -} - -void Max7219_LED_Off(const uint8_t x, const uint8_t y) { - if (x > (MAX7219_X_LEDS - 1) || y > (MAX7219_Y_LEDS - 1)) return Max7219_Error(PSTR("Max7219_LED_Off"), x, y); - Max7219_LED_Set(x, y, false); -} - -void Max7219_LED_Toggle(const uint8_t x, const uint8_t y) { - if (x > (MAX7219_X_LEDS - 1) || y > (MAX7219_Y_LEDS - 1)) return Max7219_Error(PSTR("Max7219_LED_Toggle"), x, y); - Max7219_LED_Set(x, y, !BIT_7219(x, y)); -} - -inline void _Max7219_Set_Digit_Segments(const uint8_t digit, const uint8_t val) { - LEDs[digit] = val; - SEND_7219(digit); -} - -/* - * void Max7219_Set_Row( const uint8_t col, const uint32_t val) plots the low order bits of - * val to the specified row of the Max7219 matrix. With 4 Max7219 units in the chain, it - * is possible to display an entire 32-bit number with one call to the function (if appropriately - * orientated). +/** + * 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_Row(const uint8_t row, const uint32_t val) { - if (row >= MAX7219_Y_LEDS) return Max7219_Error(PSTR("Max7219_Set_Row"), row); - uint32_t mask = 0x0000001; - for(uint8_t x = 0; x < MAX7219_X_LEDS; x++) { - if (val & mask) - SET_PIXEL_7219(MAX7219_X_LEDS-1-x, row); - else - CLEAR_PIXEL_7219(MAX7219_X_LEDS-1-x, row); - mask <<= 1; +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; } - #if _ROT == 90 || _ROT == 270 - for(uint8_t x = 0; x < 8; x++) - SEND_7219(x); // force all columns out to the Max7219 chips and strobe them - #else - SEND_7219(row); // force the single column out to the Max7219 chips and strobe them - #endif - return; + send_column(col); } -void Max7219_Clear_Row(const uint8_t row) { - if (row > 7) return Max7219_Error(PSTR("Max7219_Clear_Row"), row); - #if _ROT == 90 || _ROT == 270 - for (uint8_t col = 0; col < 8; col++) Max7219_LED_Off(col, row); - #else - _Max7219_Set_Digit_Segments(row, 0); - #endif -} - -/* - * void Max7219_Set_Column( const uint8_t col, const uint32_t val) plots the low order bits of - * val to the specified column of the Max7219 matrix. With 4 Max7219 units in the chain, it - * is possible to display an entire 32-bit number with one call to the function (if appropriately - * orientated). - */ -void Max7219_Set_Column(const uint8_t col, const uint32_t val) { - if (col >= MAX7219_X_LEDS) return Max7219_Error(PSTR("Max7219_Set_Column"), col); - uint32_t mask = 0x0000001; - for(uint8_t y = 0; y < MAX7219_Y_LEDS; y++) { - if (val & mask) - SET_PIXEL_7219(col, MAX7219_Y_LEDS-1-y); - else - CLEAR_PIXEL_7219(col, MAX7219_Y_LEDS-1-y); - mask <<= 1; - } - #if _ROT == 90 || _ROT == 270 - SEND_7219(col); // force the column out to the Max7219 chips and strobe them - #else - for(uint8_t yy = 0; yy < 8; yy++) - SEND_7219(yy); // force all columns out to the Max7219 chips and strobe them - #endif - return; -} - -void Max7219_Clear_Column(const uint8_t col) { - if (col >= MAX7219_X_LEDS) return Max7219_Error(PSTR("Max7219_Clear_Column"), col); - - for(uint8_t yy = 0; yy < MAX7219_Y_LEDS; yy++) - CLEAR_PIXEL_7219(col, yy); - - #if _ROT == 90 || _ROT == 270 - SEND_7219(col); // force the column out to the Max7219 chips and strobe them - #else - for(uint8_t y = 0; y < 8; y++) - SEND_7219(y); // force all columns out to the Max7219 chips and strobe them - #endif - return; -} - -void Max7219_Clear() { - for (uint8_t i = 0; i <= 7; i++) { // Clear LED bitmap - for (uint8_t j = 0; j < MAX7219_NUMBER_UNITS; j++) - LEDs[i + j * 8] = 0x00; - SEND_7219(i); - } -} - -void Max7219_Set_Rows_16bits(const uint8_t y, uint32_t val) { +void Max7219::set_rows_16bits(const uint8_t y, uint32_t val) { #if MAX7219_X_LEDS == 8 - if (y > MAX7219_Y_LEDS - 2) return Max7219_Error(PSTR("Max7219_Set_Rows_16bits"), y, val); - Max7219_Set_Row(y + 1, val); val >>= 8; - Max7219_Set_Row(y + 0, val); + 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 Max7219_Error(PSTR("Max7219_Set_Rows_16bits"), y, val); - Max7219_Set_Row(y, val); + if (y > MAX7219_Y_LEDS - 1) return error(PSTR("set_rows_16bits"), y, val); + set_row(y, val); #endif } -void Max7219_Set_Rows_32bits(const uint8_t y, uint32_t val) { +void Max7219::set_rows_32bits(const uint8_t y, uint32_t val) { #if MAX7219_X_LEDS == 8 - if (y > MAX7219_Y_LEDS - 4) return Max7219_Error(PSTR("Max7219_Set_Rows_32bits"), y, val); - Max7219_Set_Row(y + 3, val); val >>= 8; - Max7219_Set_Row(y + 2, val); val >>= 8; - Max7219_Set_Row(y + 1, val); val >>= 8; - Max7219_Set_Row(y + 0, val); + 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 Max7219_Error(PSTR("Max7219_Set_Rows_32bits"), y, val); - Max7219_Set_Row(y + 1, val); val >>= 16; - Max7219_Set_Row(y + 0, val); + 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 Max7219_Error(PSTR("Max7219_Set_Rows_32bits"), y, val); - Max7219_Set_Row(y, val); + if (y > MAX7219_Y_LEDS - 1) return error(PSTR("set_rows_32bits"), y, val); + set_row(y, val); #endif } -void Max7219_Set_Columns_16bits(const uint8_t x, uint32_t val) { +void Max7219::set_columns_16bits(const uint8_t x, uint32_t val) { #if MAX7219_Y_LEDS == 8 - if (x > MAX7219_X_LEDS - 2) return Max7219_Error(PSTR("Max7219_Set_Columns_16bits"), x, val); - Max7219_Set_Column(x + 0, val); val >>= 8; - Max7219_Set_Column(x + 1, val); + 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 Max7219_Error(PSTR("Max7219_Set_Columns_16bits"), x, val); - Max7219_Set_Column(x, val); + if (x > MAX7219_X_LEDS - 1) return error(PSTR("set_columns_16bits"), x, val); + set_column(x, val); #endif } -void Max7219_Set_Columns_32bits(const uint8_t x, uint32_t val) { +void Max7219::set_columns_32bits(const uint8_t x, uint32_t val) { #if MAX7219_Y_LEDS == 8 - if (x > MAX7219_X_LEDS - 4) return Max7219_Error(PSTR("Max7219_Set_Rows_32bits"), x, val); - Max7219_Set_Column(x + 3, val); val >>= 8; - Max7219_Set_Column(x + 2, val); val >>= 8; - Max7219_Set_Column(x + 1, val); val >>= 8; - Max7219_Set_Column(x + 0, val); + 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 Max7219_Error(PSTR("Max7219_Set_Rows_32bits"), x, val); - Max7219_Set_Column(x + 1, val); val >>= 16; - Max7219_Set_Column(x + 0, val); + 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 Max7219_Error(PSTR("Max7219_Set_Rows_32bits"), x, val); - Max7219_Set_Column(x, val); + if (x > MAX7219_X_LEDS - 1) return error(PSTR("set_rows_32bits"), x, val); + set_column(x, val); #endif } -void Max7219_register_setup() { - // Initialize the Max7219 - for(int i=0; i < MAX7219_NUMBER_UNITS; i++) - Max7219(max7219_reg_scanLimit, 0x07); - Max7219_pulse_load(); // tell the chips to load the clocked out data +// 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 - for(int i=0; i < MAX7219_NUMBER_UNITS; i++) - Max7219(max7219_reg_decodeMode, 0x00); // using an led matrix (not digits) - Max7219_pulse_load(); // tell the chips to load the clocked out data + 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 - for(int i=0; i < MAX7219_NUMBER_UNITS; i++) - Max7219(max7219_reg_shutdown, 0x01); // not in shutdown mode - Max7219_pulse_load(); // tell the chips to load the clocked out data - for(int i=0; i < MAX7219_NUMBER_UNITS; i++) - Max7219(max7219_reg_displayTest, 0x00); // no display test - Max7219_pulse_load(); // tell the chips to load the clocked out data + 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 - for(int i=0; i < MAX7219_NUMBER_UNITS; i++) - Max7219(max7219_reg_intensity, 0x01 & 0x0F); // the first 0x0F is the value you can set + 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 - Max7219_pulse_load(); // tell the chips to load the clocked out data + 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 = MAX7219_X_LEDS * MAX7219_Y_LEDS; i--;) { - Max7219_LED_Set(px, py, on); + led_set(px, py, on); delay(del); const int8_t x = px + way[dir], y = py + way[dir + 1]; if (!WITHIN(x, 0, MAX7219_X_LEDS-1) || !WITHIN(y, 0, MAX7219_Y_LEDS-1) || BIT_7219(x, y) == on) dir = (dir + 2) & 0x7; @@ -360,10 +409,10 @@ void Max7219_register_setup() { #else - inline void Max7219_sweep(const int8_t dir, const uint16_t ms, const bool on) { + 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) { - Max7219_Set_Column(x, on ? 0xFFFFFFFF : 0x00000000); + set_column(x, on ? 0xFFFFFFFF : 0x00000000); delay(ms); } } @@ -371,33 +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); - Max7219_pulse_load(); // tell the chips to load the clocked out data + 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 } @@ -409,58 +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) { +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 - Max7219_LED_Off(v1 & 0x7, y + (v1 >= 8)); - Max7219_LED_On(v2 & 0x7, y + (v2 >= 8)); + led_off(v1 & 0x7, y + (v1 >= 8)); + led_on(v2 & 0x7, y + (v2 >= 8)); #else - Max7219_LED_Off(y, v1 & 0xF); // The Max7219 Y-Axis has at least 16 LED's. So use a single column - Max7219_LED_On(y, v2 & 0xF); + led_off(y, v1 & 0xF); // At least 16 LEDs down. Use a single column. + led_on(y, v2 & 0xF); #endif - #else // LED matrix has at least 16 LED's on the X-Axis. Use single line of LED's - Max7219_LED_Off(v1 & 0xf, y); - Max7219_LED_On(v2 & 0xf, y); + #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) { +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) - Max7219_LED_Off(n & 0x7, y + (n >= 8)); + 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)); + 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) - Max7219_LED_Off(y, n & 0xF); + led_off(y, n & 0xF); if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF) - Max7219_LED_On(y, n & 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) - Max7219_LED_Off(n & 0xf, y); + led_off(n & 0xF, y); if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF) - Max7219_LED_On(n & 0xf, y); + 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++) #if MAX7219_X_LEDS == 8 #if MAX7219_Y_LEDS == 8 - Max7219_LED_Set(i >> 1, y + (i & 1), nv >= ov); // single 8x8 LED matrix. Use two lines to get 16 LED's + led_set(i >> 1, y + (i & 1), nv >= ov); // single 8x8 LED matrix. Use two lines to get 16 LED's #else - Max7219_LED_Set(y, i, nv >= ov); // The Max7219 Y-Axis has at least 16 LED's. So use a single column + led_set(y, i, nv >= ov); // The Max7219 Y-Axis has at least 16 LED's. So use a single column #endif #else - Max7219_LED_Set(i, y, nv >= ov); // LED matrix has at least 16 LED's on the X-Axis. Use single line of LED's + 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 @@ -491,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(MAX7219_X_LEDS - 1, MAX7219_Y_LEDS - 1); + led_toggle(MAX7219_X_LEDS - 1, MAX7219_Y_LEDS - 1); next_blink = ms + 1000; } #endif @@ -506,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; } @@ -516,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 @@ -524,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 @@ -535,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 ba8cf05d93..3523eef40f 100644 --- a/Marlin/Max7219_Debug_LEDs.h +++ b/Marlin/Max7219_Debug_LEDs.h @@ -31,18 +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 + * 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 @@ -63,85 +78,77 @@ #define max7219_reg_shutdown 0x0C #define max7219_reg_displayTest 0x0F -void Max7219_init(); -void Max7219_PutByte(uint8_t data); -void Max7219_pulse_load(); +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 LEDs in a single column -void Max7219_Set_Column(const uint8_t col, const uint32_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 LEDs in a single row -void Max7219_Set_Row(const uint8_t row, const uint32_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); } -// 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 -void Max7219_Set_Rows_16bits(const uint8_t y, uint32_t val); -void Max7219_Set_Rows_32bits(const uint8_t y, uint32_t val); -void Max7219_Set_Columns_16bits(const uint8_t x, uint32_t val); -void Max7219_Set_Columns_32bits(const uint8_t x, uint32_t val); + // Update a single native line on all units + static void refresh_line(const uint8_t line); -// Quickly clear the whole matrix -void Max7219_Clear(); + // Update a single native line on just one unit + static void refresh_unit_line(const uint8_t line); -// Apply custom code to update the matrix -void Max7219_idle_tasks(); + // 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); -#ifndef MAX7219_ROTATE - #define MAX7219_ROTATE 0 -#endif -#define _ROT ((MAX7219_ROTATE + 360) % 360) -#if _ROT == 0 - #define MAX7219_UPDATE_AXIS y // Fast line update axis for this orientation of the matrix display - #define MAX7219_X_LEDS (8 * MAX7219_NUMBER_UNITS) - #define MAX7219_Y_LEDS 8 - #define XOR_7219(x, y) LEDs[y + (x >> 3) * 8] ^= _BV(7 - (x & 0x07)) - #define SET_PIXEL_7219(x, y) LEDs[y + (x >> 3) * 8] |= _BV(7 - (x & 0x07)) - #define CLEAR_PIXEL_7219(x, y) LEDs[y + (x >> 3) * 8] &= (_BV(7 - (x & 0x07)) ^ 0xff) - #define BIT_7219(x, y) TEST(LEDs[y + (x >> 3) * 8], 7 - (x & 0x07)) - #define SEND_7219(R) do {for(int8_t jj = 0; jj < MAX7219_NUMBER_UNITS; jj++) Max7219(max7219_reg_digit0 + (R & 0x7), LEDs[(R & 0x7) + jj * 8]); Max7219_pulse_load(); } while (0); -#elif _ROT == 90 - #define MAX7219_UPDATE_AXIS x // Fast line update axis for this orientation of the matrix display - #define MAX7219_X_LEDS 8 - #define MAX7219_Y_LEDS (8 * MAX7219_NUMBER_UNITS) - #define XOR_7219(x, y) LEDs[x + (((MAX7219_Y_LEDS - 1 - y) >> 3) * 8)] ^= _BV((y & 0x7)) - #define SET_PIXEL_7219(x, y) LEDs[x + (((MAX7219_Y_LEDS - 1 - y) >> 3) * 8)] |= _BV((y & 0x7)) - #define CLEAR_PIXEL_7219(x, y) LEDs[x + (((MAX7219_Y_LEDS - 1 - y) >> 3) * 8)] &= (_BV((y & 0x7)) ^ 0xff) - #define BIT_7219(x, y) TEST(LEDs[x + (((MAX7219_Y_LEDS - 1 - y) >> 3) * 8)], (y & 0x7)) - #define SEND_7219(R) do {for(int8_t jj = 0; jj < MAX7219_NUMBER_UNITS; jj++) Max7219(max7219_reg_digit0 + (R & 0x7), LEDs[(R & 0x7) + jj * 8]); Max7219_pulse_load(); } while (0); -#elif _ROT == 180 - #define MAX7219_UPDATE_AXIS y // Fast line update axis for this orientation of the matrix display - #define MAX7219_X_LEDS (8 * MAX7219_NUMBER_UNITS) - #define MAX7219_Y_LEDS 8 - #define XOR_7219(x, y) LEDs[y + ((MAX7219_X_LEDS - 1 - x) >> 3) * 8] ^= _BV((x & 0x07)) - #define SET_PIXEL_7219(x, y) LEDs[y + ((MAX7219_X_LEDS - 1 - x) >> 3) * 8] |= _BV((x & 0x07)) - #define CLEAR_PIXEL_7219(x, y) LEDs[y + ((MAX7219_X_LEDS - 1 - x) >> 3) * 8] &= (_BV((x & 0x07)) ^ 0xff) - #define BIT_7219(x, y) TEST(LEDs[y + ((MAX7219_X_LEDS - 1 - x) >> 3) * 8], ((x & 0x07))) - #define SEND_7219(R) do {for(int8_t jj = 0; jj < MAX7219_NUMBER_UNITS; jj++) Max7219(max7219_reg_digit7 - (R & 0x7), LEDs[(R & 0x7) + jj * 8]); Max7219_pulse_load(); } while (0); -#elif _ROT == 270 - #define MAX7219_UPDATE_AXIS x // Fast line update axis for this orientation of the matrix display - #define MAX7219_X_LEDS 8 - #define MAX7219_Y_LEDS (8 * MAX7219_NUMBER_UNITS) - #define XOR_7219(x, y) LEDs[x + (y >> 3) * 8] ^= _BV(7 - (y & 0x7)) - #define SET_PIXEL_7219(x, y) LEDs[x + (y >> 3) * 8] |= _BV(7 - (y & 0x7)) - #define CLEAR_PIXEL_7219(x, y) LEDs[x + (y >> 3) * 8] &= (_BV(7 - (y & 0x7)) ^ 0xff) - #define BIT_7219(x, y) TEST(LEDs[x + ( y >> 3) * 8], 7 - (y & 0x7)) - #define SEND_7219(R) do {for(int8_t jj = 0; jj < MAX7219_NUMBER_UNITS; jj++) Max7219(max7219_reg_digit7 - (R & 0x7), LEDs[(R & 0x7) + jj * 8]); Max7219_pulse_load(); } while (0); -#else - #error "MAX7219_ROTATE must be a multiple of +/- 90°." -#endif + // 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); -extern uint8_t LEDs[8*MAX7219_NUMBER_UNITS]; + // 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); -#endif // __MAX7219_DEBUG_LEDS_H__ + // 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 47d6a29776..7538ac49d3 100644 --- a/Marlin/SanityCheck.h +++ b/Marlin/SanityCheck.h @@ -403,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 @@ -465,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) @@ -527,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 /** @@ -686,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) \ @@ -695,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 /** @@ -717,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 */ @@ -761,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 @@ -1203,6 +1254,7 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE, #endif #endif #endif + /** * Endstop Tests */ @@ -1210,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 @@ -1523,7 +1575,7 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE, #endif #if ENABLED(STEALTHCHOP) && !HAS_STEALTHCHOP #error "STEALTHCHOP requires TMC2130 or TMC2208 stepper drivers." - #endif +#endif /** * Digipot requirement @@ -1536,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 ee96bd55f3..e0edfff727 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -35,7 +35,7 @@ /** * Marlin release version identifier */ - #define SHORT_BUILD_VERSION "TM3D 1.1.8_R7" + #define SHORT_BUILD_VERSION "TM3D 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-28" + #define STRING_DISTRIBUTION_DATE "2018-09-30" /** * 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/configuration_store.cpp b/Marlin/configuration_store.cpp index c042a418f8..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); @@ -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); @@ -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 @@ -2219,8 +2325,8 @@ void MarlinSettings::reset() { SERIAL_ECHOPAIR("EEPROM can hold ", calc_num_meshes()); SERIAL_ECHOLNPGM(" meshes.\n"); } - -// ubl.report_current_mesh(PORTVAR_SOLO); // This is too verbose for large mesh's. A better (more terse) + + //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) @@ -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) { diff --git a/Marlin/drivers.h b/Marlin/drivers.h index 0aa424c67d..3a8ff4a2a0 100644 --- a/Marlin/drivers.h +++ b/Marlin/drivers.h @@ -40,52 +40,21 @@ #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(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_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)) -#if ENABLED(X_DUAL_STEPPER_DRIVERS) || ENABLED(DUAL_X_CARRIAGE) - #define AXIS_DRIVER_TYPE_X2(T) AXIS_DRIVER_TYPE(X2,T) -#else - #define AXIS_DRIVER_TYPE_X2(T) false -#endif -#if ENABLED(Y_DUAL_STEPPER_DRIVERS) - #define AXIS_DRIVER_TYPE_Y2(T) AXIS_DRIVER_TYPE(Y2,T) -#else - #define AXIS_DRIVER_TYPE_Y2(T) false -#endif -#if ENABLED(Z_DUAL_STEPPER_DRIVERS) - #define AXIS_DRIVER_TYPE_Z2(T) AXIS_DRIVER_TYPE(Z2,T) -#else - #define AXIS_DRIVER_TYPE_Z2(T) false -#endif -#if E_STEPPERS > 0 - #define AXIS_DRIVER_TYPE_E0(T) AXIS_DRIVER_TYPE(E0,T) -#else - #define AXIS_DRIVER_TYPE_E0(T) false -#endif -#if E_STEPPERS > 1 - #define AXIS_DRIVER_TYPE_E1(T) AXIS_DRIVER_TYPE(E1,T) -#else - #define AXIS_DRIVER_TYPE_E1(T) false -#endif -#if E_STEPPERS > 2 - #define AXIS_DRIVER_TYPE_E2(T) AXIS_DRIVER_TYPE(E2,T) -#else - #define AXIS_DRIVER_TYPE_E2(T) false -#endif -#if E_STEPPERS > 3 - #define AXIS_DRIVER_TYPE_E3(T) AXIS_DRIVER_TYPE(E3,T) -#else - #define AXIS_DRIVER_TYPE_E3(T) false -#endif -#if E_STEPPERS > 4 - #define AXIS_DRIVER_TYPE_E4(T) AXIS_DRIVER_TYPE(E4,T) -#else - #define AXIS_DRIVER_TYPE_E4(T) false -#endif +#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) || \ @@ -96,10 +65,9 @@ // Test for supported TMC drivers that require advanced configuration // Does not match standalone configurations -#define HAS_TRINAMIC ( HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2208) || HAS_DRIVER(TMC2660) ) +#define HAS_TRINAMIC (HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2208)) #define AXIS_IS_TMC(A) ( AXIS_DRIVER_TYPE_##A(TMC2130) || \ - AXIS_DRIVER_TYPE_##A(TMC2208) || \ - AXIS_DRIVER_TYPE_##A(TMC2660) ) + AXIS_DRIVER_TYPE_##A(TMC2208) ) #endif // _DRIVERS_H_ diff --git a/Marlin/endstops.cpp b/Marlin/endstops.cpp index f345e8f45b..39fbc80134 100644 --- a/Marlin/endstops.cpp +++ b/Marlin/endstops.cpp @@ -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()) hit_on_purpose(); - else kill(PSTR(MSG_ERR_HOMING_FAILED)); -} +#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 @@ -306,12 +308,16 @@ void Endstops::event_handler() { 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 diff --git a/Marlin/endstops.h b/Marlin/endstops.h index 97dd62443f..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, @@ -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/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 b35164f672..3ed5653c49 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 @@ -468,14 +471,12 @@ #ifndef MSG_EXTRA_FAN_SPEED #define MSG_EXTRA_FAN_SPEED _UxGT("Extra fan speed") #endif - #ifndef MSG_LASER_ON #define MSG_LASER_ON _UxGT("Laser On") #endif #ifndef MSG_LASER_OFF #define MSG_LASER_OFF _UxGT("Laser Off") #endif - #ifndef MSG_FLOW #define MSG_FLOW _UxGT("Flow") #endif @@ -1063,6 +1064,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 9479788aa2..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 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/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 428dc047c8..e3f67059fa 100644 --- a/Marlin/pins_EINSY_RAMBO.h +++ b/Marlin/pins_EINSY_RAMBO.h @@ -118,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_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 19acc6e014..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 diff --git a/Marlin/status_screen_lite_ST7920.h b/Marlin/status_screen_lite_ST7920.h index 144591da70..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(); @@ -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 a45146b289..cde4c31a23 100644 --- a/Marlin/stepper_indirection.cpp +++ b/Marlin/stepper_indirection.cpp @@ -35,6 +35,8 @@ #include "MarlinConfig.h" +#include "stepper.h" + // // TMC26X Driver objects and inits // @@ -288,8 +290,7 @@ #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 AXIS_DRIVER_TYPE(X, TMC2208) @@ -372,37 +373,81 @@ void tmc2208_serial_begin() { #if AXIS_DRIVER_TYPE(X, TMC2208) - X_HARDWARE_SERIAL.begin(115200); + #ifdef X_HARDWARE_SERIAL + X_HARDWARE_SERIAL.begin(115200); + #else + stepperX.beginSerial(115200); + #endif #endif #if AXIS_DRIVER_TYPE(X2, TMC2208) - X2_HARDWARE_SERIAL.begin(115200); + #ifdef X2_HARDWARE_SERIAL + X2_HARDWARE_SERIAL.begin(115200); + #else + stepperX2.beginSerial(115200); + #endif #endif #if AXIS_DRIVER_TYPE(Y, TMC2208) - Y_HARDWARE_SERIAL.begin(115200); + #ifdef Y_HARDWARE_SERIAL + Y_HARDWARE_SERIAL.begin(115200); + #else + stepperY.beginSerial(115200); + #endif #endif #if AXIS_DRIVER_TYPE(Y2, TMC2208) - Y2_HARDWARE_SERIAL.begin(115200); + #ifdef Y2_HARDWARE_SERIAL + Y2_HARDWARE_SERIAL.begin(115200); + #else + stepperY2.beginSerial(115200); + #endif #endif #if AXIS_DRIVER_TYPE(Z, TMC2208) - Z_HARDWARE_SERIAL.begin(115200); + #ifdef Z_HARDWARE_SERIAL + Z_HARDWARE_SERIAL.begin(115200); + #else + stepperZ.beginSerial(115200); + #endif #endif #if AXIS_DRIVER_TYPE(Z2, TMC2208) - Z2_HARDWARE_SERIAL.begin(115200); + #ifdef Z2_HARDWARE_SERIAL + Z2_HARDWARE_SERIAL.begin(115200); + #else + stepperZ2.beginSerial(115200); + #endif #endif #if AXIS_DRIVER_TYPE(E0, TMC2208) - E0_HARDWARE_SERIAL.begin(115200); + #ifdef E0_HARDWARE_SERIAL + E0_HARDWARE_SERIAL.begin(115200); + #else + stepperE0.beginSerial(115200); + #endif #endif #if AXIS_DRIVER_TYPE(E1, TMC2208) - E1_HARDWARE_SERIAL.begin(115200); + #ifdef E1_HARDWARE_SERIAL + E1_HARDWARE_SERIAL.begin(115200); + #else + stepperE1.beginSerial(115200); + #endif #endif #if AXIS_DRIVER_TYPE(E2, TMC2208) - E2_HARDWARE_SERIAL.begin(115200); + #ifdef E2_HARDWARE_SERIAL + E2_HARDWARE_SERIAL.begin(115200); + #else + stepperE2.beginSerial(115200); + #endif #endif #if AXIS_DRIVER_TYPE(E3, TMC2208) - E3_HARDWARE_SERIAL.begin(115200); + #ifdef E3_HARDWARE_SERIAL + E3_HARDWARE_SERIAL.begin(115200); + #else + stepperE3.beginSerial(115200); + #endif #endif #if AXIS_DRIVER_TYPE(E4, TMC2208) - E4_HARDWARE_SERIAL.begin(115200); + #ifdef E4_HARDWARE_SERIAL + E4_HARDWARE_SERIAL.begin(115200); + #else + stepperE4.beginSerial(115200); + #endif #endif } @@ -535,6 +580,7 @@ void reset_stepper_drivers() { #if HAS_DRIVER(L6470) L6470_init_to_defaults(); #endif + stepper.set_directions(); } // diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index 1e765a242a..665e5b5ec9 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -1743,6 +1743,10 @@ 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(); @@ -1786,14 +1790,12 @@ void Temperature::readings_ready() { 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 < + const bool heater_on = (target_temperature[e] > 0) #if ENABLED(PIDTEMP) - soft_pwm_amount[e] - #else - target_temperature[e] + || (soft_pwm_amount[e] > 0) #endif ; - if (rawtemp > maxttemp_raw[e] * tdir && heater_on) max_temp_error(e); + 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) @@ -1812,20 +1814,18 @@ void Temperature::readings_ready() { #else #define GEBED >= #endif - const bool bed_on = 0 < + const bool bed_on = (target_temperature_bed > 0) #if ENABLED(PIDTEMPBED) - soft_pwm_amount_bed - #else - target_temperature_bed + || (soft_pwm_amount_bed > 0) #endif ; - if (current_temperature_bed_raw GEBED bed_maxttemp_raw && bed_on) max_temp_error(-1); + 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 @@ -1887,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) @@ -2245,8 +2241,8 @@ void Temperature::isr() { 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 += ((unsigned long)HAL_READ_ADC() << 7); // Add new ADC reading, scaled by 128 + 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 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/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_G29.cpp b/Marlin/ubl_G29.cpp index 2345da715e..c401fa6962 100644 --- a/Marlin/ubl_G29.cpp +++ b/Marlin/ubl_G29.cpp @@ -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 4e3f138a06..5b8d293d6c 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -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 @@ -1462,6 +1462,7 @@ void lcd_quick_feedback(const bool clear_buttons) { #endif #endif #endif // FAN_COUNT > 0 + // // Laser ON/OFF: // @@ -1469,6 +1470,7 @@ void lcd_quick_feedback(const bool clear_buttons) { MENU_ITEM(gcode, MSG_LASER_ON, PSTR(" M3 ")); MENU_ITEM(gcode, MSG_LASER_OFF, PSTR(" M5 ")); #endif + // // Flow: // Flow [1-5]: @@ -2681,6 +2683,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 // @@ -3076,7 +3085,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 @@ -3106,7 +3115,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 @@ -3513,10 +3522,12 @@ void lcd_quick_feedback(const bool clear_buttons) { #endif #endif #endif // FAN_COUNT > 0 - #if ENABLED(FAN_AS_LASER) - MENU_ITEM(gcode, MSG_LASER_ON, PSTR("M3")); - MENU_ITEM(gcode, MSG_LASER_OFF, PSTR("M5")); + + #if ENABLED(FAN_AS_LASER) + MENU_ITEM(gcode, MSG_LASER_ON, PSTR("M3")); + MENU_ITEM(gcode, MSG_LASER_OFF, PSTR("M5")); #endif + // // Autotemp, Min, Max, Fact // diff --git a/Marlin/ultralcd_impl_DOGM.h b/Marlin/ultralcd_impl_DOGM.h index 1c2844c72f..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