Browse Source

Backlash cleanup (#13659)

…And save backlash, fil. sensor, ExtUI userdata to EEPROM.
Marcio Teixeira 5 years ago
parent
commit
15357af67c

+ 9
- 7
Marlin/src/Marlin.cpp View File

@@ -939,6 +939,15 @@ void setup() {
939 939
 
940 940
   queue_setup();
941 941
 
942
+  // UI must be initialized before EEPROM
943
+  // (because EEPROM code calls the UI).
944
+  ui.init();
945
+  ui.reset_status();
946
+
947
+  #if HAS_SPI_LCD && ENABLED(SHOW_BOOTSCREEN)
948
+    ui.show_bootscreen();
949
+  #endif
950
+
942 951
   #if ENABLED(SDIO_SUPPORT) && SD_DETECT_PIN == -1
943 952
     // Auto-mount the SD for EEPROM.dat emulation
944 953
     if (!card.isDetected()) card.initsd();
@@ -1044,13 +1053,6 @@ void setup() {
1044 1053
     fanmux_init();
1045 1054
   #endif
1046 1055
 
1047
-  ui.init();
1048
-  ui.reset_status();
1049
-
1050
-  #if HAS_SPI_LCD && ENABLED(SHOW_BOOTSCREEN)
1051
-    ui.show_bootscreen();
1052
-  #endif
1053
-
1054 1056
   #if ENABLED(MIXING_EXTRUDER)
1055 1057
     mixer.init();
1056 1058
   #endif

+ 139
- 0
Marlin/src/feature/backlash.cpp View File

@@ -0,0 +1,139 @@
1
+/**
2
+ * Marlin 3D Printer Firmware
3
+ * Copyright (C) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
4
+ *
5
+ * Based on Sprinter and grbl.
6
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
7
+ *
8
+ * This program is free software: you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation, either version 3 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+
23
+#include "../Marlin.h"
24
+
25
+#if ENABLED(BACKLASH_COMPENSATION)
26
+
27
+#include "backlash.h"
28
+#include "../module/planner.h"
29
+
30
+#if ENABLED(BACKLASH_GCODE)
31
+  uint8_t Backlash::correction = (BACKLASH_CORRECTION) * 0xFF;
32
+  #ifdef BACKLASH_DISTANCE_MM
33
+    float Backlash::distance_mm[XYZ] = BACKLASH_DISTANCE_MM;
34
+  #endif
35
+  #ifdef BACKLASH_SMOOTHING_MM
36
+    float Backlash::smoothing_mm = BACKLASH_SMOOTHING_MM;
37
+  #endif
38
+#endif
39
+
40
+#if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
41
+  float Backlash::measured_mm[XYZ] = { 0 };
42
+  uint8_t Backlash::measured_count[XYZ] = { 0 };
43
+#endif
44
+
45
+Backlash backlash;
46
+
47
+/**
48
+ * To minimize seams in the printed part, backlash correction only adds
49
+ * steps to the current segment (instead of creating a new segment, which
50
+ * causes discontinuities and print artifacts).
51
+ *
52
+ * With a non-zero BACKLASH_SMOOTHING_MM value the backlash correction is
53
+ * spread over multiple segments, smoothing out artifacts even more.
54
+ */
55
+
56
+void Backlash::add_correction_steps(const int32_t &da, const int32_t &db, const int32_t &dc, const uint8_t dm, block_t * const block) {
57
+  static uint8_t last_direction_bits;
58
+  uint8_t changed_dir = last_direction_bits ^ dm;
59
+  // Ignore direction change if no steps are taken in that direction
60
+  if (da == 0) CBI(changed_dir, X_AXIS);
61
+  if (db == 0) CBI(changed_dir, Y_AXIS);
62
+  if (dc == 0) CBI(changed_dir, Z_AXIS);
63
+  last_direction_bits ^= changed_dir;
64
+
65
+  if (correction == 0) return;
66
+
67
+  #ifdef BACKLASH_SMOOTHING_MM
68
+    // The segment proportion is a value greater than 0.0 indicating how much residual_error
69
+    // is corrected for in this segment. The contribution is based on segment length and the
70
+    // smoothing distance. Since the computation of this proportion involves a floating point
71
+    // division, defer computation until needed.
72
+    float segment_proportion = 0;
73
+
74
+    // Residual error carried forward across multiple segments, so correction can be applied
75
+    // to segments where there is no direction change.
76
+    static int32_t residual_error[XYZ] = { 0 };
77
+  #else
78
+    // No leftover residual error from segment to segment
79
+    int32_t residual_error[XYZ] = { 0 };
80
+    // No direction change, no correction.
81
+    if (!changed_dir) return;
82
+  #endif
83
+
84
+  const float f_corr = float(correction) / 255.0f;
85
+
86
+  LOOP_XYZ(axis) {
87
+    if (distance_mm[axis]) {
88
+      const bool reversing = TEST(dm,axis);
89
+
90
+      // When an axis changes direction, add axis backlash to the residual error
91
+      if (TEST(changed_dir, axis))
92
+        residual_error[axis] += (reversing ? -f_corr : f_corr) * distance_mm[axis] * planner.settings.axis_steps_per_mm[axis];
93
+
94
+      // Decide how much of the residual error to correct in this segment
95
+      int32_t error_correction = residual_error[axis];
96
+      #ifdef BACKLASH_SMOOTHING_MM
97
+        if (error_correction && smoothing_mm != 0) {
98
+          // Take up a portion of the residual_error in this segment, but only when
99
+          // the current segment travels in the same direction as the correction
100
+          if (reversing == (error_correction < 0)) {
101
+            if (segment_proportion == 0)
102
+              segment_proportion = MIN(1.0f, block->millimeters / smoothing_mm);
103
+            error_correction = ceil(segment_proportion * error_correction);
104
+          }
105
+          else
106
+            error_correction = 0; // Don't take up any backlash in this segment, as it would subtract steps
107
+        }
108
+      #endif
109
+      // Making a correction reduces the residual error and modifies delta_mm
110
+      if (error_correction) {
111
+        block->steps[axis] += ABS(error_correction);
112
+        residual_error[axis] -= error_correction;
113
+      }
114
+    }
115
+  }
116
+}
117
+
118
+#if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
119
+  #if USES_Z_MIN_PROBE_ENDSTOP
120
+    #define TEST_PROBE_PIN (READ(Z_MIN_PROBE_PIN) != Z_MIN_PROBE_ENDSTOP_INVERTING)
121
+  #else
122
+    #define TEST_PROBE_PIN (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING)
123
+  #endif
124
+
125
+  // Measure Z backlash by raising nozzle in increments until probe deactivates
126
+  void Backlash::measure_with_probe() {
127
+    if (measured_count[Z_AXIS] == 255) return;
128
+
129
+    float start_height = current_position[Z_AXIS];
130
+    while (current_position[Z_AXIS] < (start_height + BACKLASH_MEASUREMENT_LIMIT) && TEST_PROBE_PIN)
131
+      do_blocking_move_to_z(current_position[Z_AXIS] + BACKLASH_MEASUREMENT_RESOLUTION, MMM_TO_MMS(BACKLASH_MEASUREMENT_FEEDRATE));
132
+
133
+    // The backlash from all probe points is averaged, so count the number of measurements
134
+    measured_mm[Z_AXIS] += current_position[Z_AXIS] - start_height;
135
+    measured_count[Z_AXIS]++;
136
+  }
137
+#endif
138
+
139
+#endif // BACKLASH_COMPENSATION

+ 88
- 0
Marlin/src/feature/backlash.h View File

@@ -0,0 +1,88 @@
1
+/**
2
+ * Marlin 3D Printer Firmware
3
+ * Copyright (C) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
4
+ *
5
+ * Based on Sprinter and grbl.
6
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
7
+ *
8
+ * This program is free software: you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation, either version 3 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+#pragma once
23
+
24
+#include "../inc/MarlinConfigPre.h"
25
+#include "../module/planner.h"
26
+
27
+class Backlash {
28
+public:
29
+  #if ENABLED(BACKLASH_GCODE)
30
+    static uint8_t correction;
31
+    #ifdef BACKLASH_DISTANCE_MM
32
+      static float distance_mm[XYZ];
33
+    #endif
34
+    #ifdef BACKLASH_SMOOTHING_MM
35
+      static float smoothing_mm;
36
+    #endif
37
+    static inline void set_correction(const float &v) { correction = MAX(0, MIN(1.0, v)) * all_on; }
38
+    static inline float get_correction() { return float(ui8_to_percent(correction)) / 100.0f; }
39
+  #elif ENABLED(BACKLASH_COMPENSATION)
40
+    static constexpr uint8_t correction = (BACKLASH_CORRECTION) * 0xFF;
41
+    #ifdef BACKLASH_DISTANCE_MM
42
+      static constexpr float distance_mm[XYZ] = BACKLASH_DISTANCE_MM;
43
+    #endif
44
+    #ifdef BACKLASH_SMOOTHING_MM
45
+      static constexpr float smoothing_mm = BACKLASH_SMOOTHING_MM;
46
+    #endif
47
+    static inline void set_correction(float) { }
48
+    static inline float get_correction() { return float(ui8_to_percent(correction)) / 100.0f; }
49
+  #else
50
+    static constexpr uint8_t correction = 0;
51
+    static inline void set_correction(float) { }
52
+    static inline float get_correction() { return 0; }
53
+  #endif
54
+
55
+  #if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
56
+    private:
57
+      static float measured_mm[XYZ];
58
+      static uint8_t measured_count[XYZ];
59
+    public:
60
+      static void measure_with_probe();
61
+  #endif
62
+
63
+  static inline float get_measurement(const uint8_t e) {
64
+    // Return the measurement averaged over all readings
65
+    return (
66
+      #if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
67
+        measured_count[e] > 0 ? measured_mm[e] / measured_count[e] :
68
+      #endif
69
+      0
70
+    );
71
+  }
72
+
73
+  static inline bool has_measurement(const uint8_t e) {
74
+    return (false
75
+      #if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
76
+        || (measured_count[e] > 0)
77
+      #endif
78
+    );
79
+  }
80
+
81
+  static inline bool has_any_measurement() {
82
+    return has_measurement(X_AXIS) || has_measurement(Y_AXIS) || has_measurement(Z_AXIS);
83
+  }
84
+
85
+  void add_correction_steps(const int32_t &da, const int32_t &db, const int32_t &dc, const uint8_t dm, block_t * const block);
86
+};
87
+
88
+extern Backlash backlash;

+ 1
- 1
Marlin/src/feature/runout.cpp View File

@@ -51,7 +51,7 @@ void FilamentSensorBase::filament_present(const uint8_t extruder) {
51 51
   uint8_t FilamentSensorEncoder::motion_detected;
52 52
 #endif
53 53
 
54
-#if FILAMENT_RUNOUT_DISTANCE_MM > 0
54
+#ifdef FILAMENT_RUNOUT_DISTANCE_MM
55 55
   float RunoutResponseDelayed::runout_distance_mm = FILAMENT_RUNOUT_DISTANCE_MM;
56 56
   volatile float RunoutResponseDelayed::runout_mm_countdown[EXTRUDERS];
57 57
 #else

+ 12
- 6
Marlin/src/feature/runout.h View File

@@ -78,6 +78,11 @@ class TFilamentMonitor : public FilamentMonitorBase {
78 78
       response.filament_present(extruder);
79 79
     }
80 80
 
81
+    #ifdef FILAMENT_RUNOUT_DISTANCE_MM
82
+      static inline float& runout_distance() { return response.runout_distance_mm; }
83
+      static inline void set_runout_distance(const float &mm) { response.runout_distance_mm = mm; }
84
+    #endif
85
+
81 86
     // Handle a block completion. RunoutResponseDelayed uses this to
82 87
     // add up the length of filament moved while the filament is out.
83 88
     static inline void block_completed(const block_t* const b) {
@@ -90,13 +95,13 @@ class TFilamentMonitor : public FilamentMonitorBase {
90 95
     // Give the response a chance to update its counter.
91 96
     static inline void run() {
92 97
       if (enabled && !filament_ran_out && (IS_SD_PRINTING() || print_job_timer.isRunning() || did_pause_print)) {
93
-        #if FILAMENT_RUNOUT_DISTANCE_MM > 0
98
+        #ifdef FILAMENT_RUNOUT_DISTANCE_MM
94 99
           cli(); // Prevent RunoutResponseDelayed::block_completed from accumulating here
95 100
         #endif
96 101
         response.run();
97 102
         sensor.run();
98 103
         const bool ran_out = response.has_run_out();
99
-        #if FILAMENT_RUNOUT_DISTANCE_MM > 0
104
+        #ifdef FILAMENT_RUNOUT_DISTANCE_MM
100 105
           sei();
101 106
         #endif
102 107
         if (ran_out) {
@@ -272,7 +277,7 @@ class FilamentSensorBase {
272 277
 
273 278
 /********************************* RESPONSE TYPE *********************************/
274 279
 
275
-#if FILAMENT_RUNOUT_DISTANCE_MM > 0
280
+#ifdef FILAMENT_RUNOUT_DISTANCE_MM
276 281
 
277 282
   // RunoutResponseDelayed triggers a runout event only if the length
278 283
   // of filament specified by FILAMENT_RUNOUT_DISTANCE_MM has been fed
@@ -347,11 +352,12 @@ class FilamentSensorBase {
347 352
 /********************************* TEMPLATE SPECIALIZATION *********************************/
348 353
 
349 354
 typedef TFilamentMonitor<
350
-  #if FILAMENT_RUNOUT_DISTANCE_MM > 0
355
+  #ifdef FILAMENT_RUNOUT_DISTANCE_MM
356
+    RunoutResponseDelayed,
351 357
     #if ENABLED(FILAMENT_MOTION_SENSOR)
352
-      RunoutResponseDelayed, FilamentSensorEncoder
358
+      FilamentSensorEncoder
353 359
     #else
354
-      RunoutResponseDelayed, FilamentSensorSwitch
360
+      FilamentSensorSwitch
355 361
     #endif
356 362
   #else
357 363
     RunoutResponseDebounced, FilamentSensorSwitch

+ 10
- 14
Marlin/src/gcode/calibrate/G425.cpp View File

@@ -31,6 +31,7 @@
31 31
 #include "../../module/tool_change.h"
32 32
 #include "../../module/endstops.h"
33 33
 #include "../../feature/bedlevel/bedlevel.h"
34
+#include "../../feature/backlash.h"
34 35
 
35 36
 
36 37
 /**
@@ -55,11 +56,6 @@
55 56
 #define HAS_X_CENTER BOTH(CALIBRATION_MEASURE_LEFT, CALIBRATION_MEASURE_RIGHT)
56 57
 #define HAS_Y_CENTER BOTH(CALIBRATION_MEASURE_FRONT, CALIBRATION_MEASURE_BACK)
57 58
 
58
-#if ENABLED(BACKLASH_GCODE)
59
-  extern float backlash_distance_mm[], backlash_smoothing_mm;
60
-  extern uint8_t backlash_correction;
61
-#endif
62
-
63 59
 enum side_t : uint8_t { TOP, RIGHT, FRONT, LEFT, BACK, NUM_SIDES };
64 60
 
65 61
 struct measurements_t {
@@ -79,13 +75,13 @@ struct measurements_t {
79 75
 #define TEMPORARY_SOFT_ENDSTOP_STATE(enable) REMEMBER(tes, soft_endstops_enabled, enable);
80 76
 
81 77
 #if ENABLED(BACKLASH_GCODE)
82
-  #define TEMPORARY_BACKLASH_CORRECTION(value) REMEMBER(tbst, backlash_correction, value)
78
+  #define TEMPORARY_BACKLASH_CORRECTION(value) REMEMBER(tbst, backlash.correction, value)
83 79
 #else
84 80
   #define TEMPORARY_BACKLASH_CORRECTION(value)
85 81
 #endif
86 82
 
87 83
 #if ENABLED(BACKLASH_GCODE) && defined(BACKLASH_SMOOTHING_MM)
88
-  #define TEMPORARY_BACKLASH_SMOOTHING(value) REMEMBER(tbsm, backlash_smoothing_mm, value)
84
+  #define TEMPORARY_BACKLASH_SMOOTHING(value) REMEMBER(tbsm, backlash.smoothing_mm, value)
89 85
 #else
90 86
   #define TEMPORARY_BACKLASH_SMOOTHING(value)
91 87
 #endif
@@ -454,22 +450,22 @@ inline void calibrate_backlash(measurements_t &m, const float uncertainty) {
454 450
 
455 451
     #if ENABLED(BACKLASH_GCODE)
456 452
       #if HAS_X_CENTER
457
-        backlash_distance_mm[X_AXIS] = (m.backlash[LEFT] + m.backlash[RIGHT]) / 2;
453
+        backlash.distance_mm[X_AXIS] = (m.backlash[LEFT] + m.backlash[RIGHT]) / 2;
458 454
       #elif ENABLED(CALIBRATION_MEASURE_LEFT)
459
-        backlash_distance_mm[X_AXIS] = m.backlash[LEFT];
455
+        backlash.distance_mm[X_AXIS] = m.backlash[LEFT];
460 456
       #elif ENABLED(CALIBRATION_MEASURE_RIGHT)
461
-        backlash_distance_mm[X_AXIS] = m.backlash[RIGHT];
457
+        backlash.distance_mm[X_AXIS] = m.backlash[RIGHT];
462 458
       #endif
463 459
 
464 460
       #if HAS_Y_CENTER
465
-        backlash_distance_mm[Y_AXIS] = (m.backlash[FRONT] + m.backlash[BACK]) / 2;
461
+        backlash.distance_mm[Y_AXIS] = (m.backlash[FRONT] + m.backlash[BACK]) / 2;
466 462
       #elif ENABLED(CALIBRATION_MEASURE_FRONT)
467
-        backlash_distance_mm[Y_AXIS] = m.backlash[FRONT];
463
+        backlash.distance_mm[Y_AXIS] = m.backlash[FRONT];
468 464
       #elif ENABLED(CALIBRATION_MEASURE_BACK)
469
-        backlash_distance_mm[Y_AXIS] = m.backlash[BACK];
465
+        backlash.distance_mm[Y_AXIS] = m.backlash[BACK];
470 466
       #endif
471 467
 
472
-      backlash_distance_mm[Z_AXIS] = m.backlash[TOP];
468
+      backlash.distance_mm[Z_AXIS] = m.backlash[TOP];
473 469
     #endif
474 470
   }
475 471
 

+ 13
- 31
Marlin/src/gcode/calibrate/M425.cpp View File

@@ -24,20 +24,9 @@
24 24
 
25 25
 #if ENABLED(BACKLASH_GCODE)
26 26
 
27
+#include "../../feature/backlash.h"
27 28
 #include "../../module/planner.h"
28 29
 
29
-float   backlash_distance_mm[XYZ] = BACKLASH_DISTANCE_MM;
30
-uint8_t backlash_correction = BACKLASH_CORRECTION * all_on;
31
-
32
-#ifdef BACKLASH_SMOOTHING_MM
33
-  float backlash_smoothing_mm = BACKLASH_SMOOTHING_MM;
34
-#endif
35
-
36
-#if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
37
-  float backlash_measured_mm[XYZ] = { 0 };
38
-  uint8_t backlash_measured_num[XYZ] = { 0 };
39
-#endif
40
-
41 30
 #include "../gcode.h"
42 31
 
43 32
 /**
@@ -60,59 +49,52 @@ void GcodeSuite::M425() {
60 49
   LOOP_XYZ(i) {
61 50
     if (parser.seen(axis_codes[i])) {
62 51
       planner.synchronize();
63
-      const float measured_backlash = (
64
-        #if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
65
-          backlash_measured_num[i] > 0 ? backlash_measured_mm[i] / backlash_measured_num[i] : 0
66
-        #else
67
-          0
68
-        #endif
69
-      );
70
-      backlash_distance_mm[i] = parser.has_value() ? parser.value_linear_units() : measured_backlash;
52
+      backlash.distance_mm[i] = parser.has_value() ? parser.value_linear_units() : backlash.get_measurement(i);
71 53
       noArgs = false;
72 54
     }
73 55
   }
74 56
 
75 57
   if (parser.seen('F')) {
76 58
     planner.synchronize();
77
-    backlash_correction = MAX(0, MIN(1.0, parser.value_float())) * all_on;
59
+    backlash.set_correction(parser.value_float());
78 60
     noArgs = false;
79 61
   }
80 62
 
81 63
   #ifdef BACKLASH_SMOOTHING_MM
82 64
     if (parser.seen('S')) {
83 65
       planner.synchronize();
84
-      backlash_smoothing_mm = parser.value_linear_units();
66
+      backlash.smoothing_mm = parser.value_linear_units();
85 67
       noArgs = false;
86 68
     }
87 69
   #endif
88 70
 
89 71
   if (noArgs) {
90
-    SERIAL_ECHOPGM("Backlash correction is ");
91
-    if (!backlash_correction) SERIAL_ECHOPGM("in");
72
+    SERIAL_ECHOPGM("Backlash Correction ");
73
+    if (!backlash.correction) SERIAL_ECHOPGM("in");
92 74
     SERIAL_ECHOLNPGM("active:");
93
-    SERIAL_ECHOLNPAIR("  Correction Amount/Fade-out:     F", float(ui8_to_percent(backlash_correction)) / 100, "     (F1.0 = full, F0.0 = none)");
75
+    SERIAL_ECHOLNPAIR("  Correction Amount/Fade-out:     F", backlash.get_correction(), " (F1.0 = full, F0.0 = none)");
94 76
     SERIAL_ECHOPGM("  Backlash Distance (mm):        ");
95 77
     LOOP_XYZ(a) {
96 78
       SERIAL_CHAR(' ');
97 79
       SERIAL_CHAR(axis_codes[a]);
98
-      SERIAL_ECHO(backlash_distance_mm[a]);
80
+      SERIAL_ECHO(backlash.distance_mm[a]);
99 81
       SERIAL_EOL();
100 82
     }
101 83
 
102 84
     #ifdef BACKLASH_SMOOTHING_MM
103
-      SERIAL_ECHOLNPAIR("  Smoothing (mm):                 S", backlash_smoothing_mm);
85
+      SERIAL_ECHOLNPAIR("  Smoothing (mm):                 S", backlash.smoothing_mm);
104 86
     #endif
105 87
 
106 88
     #if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
107 89
       SERIAL_ECHOPGM("  Average measured backlash (mm):");
108
-      LOOP_XYZ(a) {
109
-        if (backlash_measured_num[a] > 0) {
90
+      if (backlash.has_any_measurement()) {
91
+        LOOP_XYZ(a) if (backlash.has_measurement(a)) {
110 92
           SERIAL_CHAR(' ');
111 93
           SERIAL_CHAR(axis_codes[a]);
112
-          SERIAL_ECHO(backlash_measured_mm[a] / backlash_measured_num[a]);
94
+          SERIAL_ECHO(backlash.get_measurement(a));
113 95
         }
114 96
       }
115
-      if (!backlash_measured_num[X_AXIS] && !backlash_measured_num[Y_AXIS] && !backlash_measured_num[Z_AXIS])
97
+      else
116 98
         SERIAL_ECHOPGM(" (Not yet measured)");
117 99
       SERIAL_EOL();
118 100
     #endif

+ 9
- 0
Marlin/src/gcode/feature/runout/M412.cpp View File

@@ -32,6 +32,9 @@
32 32
  */
33 33
 void GcodeSuite::M412() {
34 34
   if (parser.seen("HS"
35
+    #ifdef FILAMENT_RUNOUT_DISTANCE_MM
36
+      "D"
37
+    #endif
35 38
     #if ENABLED(HOST_ACTION_COMMANDS)
36 39
       "R"
37 40
     #endif
@@ -42,11 +45,17 @@ void GcodeSuite::M412() {
42 45
     const bool seenR = parser.seen('R'), seenS = parser.seen('S');
43 46
     if (seenR || seenS) runout.reset();
44 47
     if (seenS) runout.enabled = parser.value_bool();
48
+    #ifdef FILAMENT_RUNOUT_DISTANCE_MM
49
+      if (parser.seen('D')) runout.set_runout_distance(parser.value_linear_units());
50
+    #endif
45 51
   }
46 52
   else {
47 53
     SERIAL_ECHO_START();
48 54
     SERIAL_ECHOPGM("Filament runout ");
49 55
     serialprintln_onoff(runout.enabled);
56
+    #ifdef FILAMENT_RUNOUT_DISTANCE_MM
57
+      SERIAL_ECHOLNPAIR("Filament runout distance (mm): ", runout.runout_distance());
58
+    #endif
50 59
   }
51 60
 }
52 61
 

+ 3
- 0
Marlin/src/inc/Conditionals_LCD.h View File

@@ -516,6 +516,9 @@
516 516
   #define GRID_MAX_POINTS ((GRID_MAX_POINTS_X) * (GRID_MAX_POINTS_Y))
517 517
 #endif
518 518
 
519
+#if ENABLED(MALYAN_LCD)
520
+  #define EXTENSIBLE_UI
521
+#endif
519 522
 #define HAS_SOFTWARE_ENDSTOPS EITHER(MIN_SOFTWARE_ENDSTOPS, MAX_SOFTWARE_ENDSTOPS)
520 523
 #define HAS_RESUME_CONTINUE   ANY(EXTENSIBLE_UI, NEWPANEL, EMERGENCY_PARSER)
521 524
 #define HAS_COLOR_LEDS        ANY(BLINKM, RGB_LED, RGBW_LED, PCA9632, PCA9533, NEOPIXEL_LED)

+ 3
- 1
Marlin/src/inc/SanityCheck.h View File

@@ -613,6 +613,8 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
613 613
     #error "FILAMENT_RUNOUT_SENSOR with NUM_RUNOUT_SENSORS > 5 requires FIL_RUNOUT6_PIN."
614 614
   #elif DISABLED(SDSUPPORT, PRINTJOB_TIMER_AUTOSTART)
615 615
     #error "FILAMENT_RUNOUT_SENSOR requires SDSUPPORT or PRINTJOB_TIMER_AUTOSTART."
616
+  #elif FILAMENT_RUNOUT_DISTANCE_MM < 0
617
+    #error "FILAMENT_RUNOUT_DISTANCE_MM must be greater than or equal to zero."
616 618
   #elif DISABLED(ADVANCED_PAUSE_FEATURE)
617 619
     static_assert(NULL == strstr(FILAMENT_RUNOUT_SCRIPT, "M600"), "ADVANCED_PAUSE_FEATURE is required to use M600 with FILAMENT_RUNOUT_SENSOR.");
618 620
   #endif
@@ -1784,7 +1786,7 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
1784 1786
   + ENABLED(OLED_PANEL_TINYBOY2) \
1785 1787
   + ENABLED(ZONESTAR_LCD) \
1786 1788
   + ENABLED(ULTI_CONTROLLER) \
1787
-  + ENABLED(EXTENSIBLE_UI)
1789
+  + (ENABLED(EXTENSIBLE_UI) && DISABLED(MALYAN_LCD))
1788 1790
   #error "Please select no more than one LCD controller option."
1789 1791
 #endif
1790 1792
 

+ 35
- 7
Marlin/src/lcd/extensible_ui/lib/example.cpp View File

@@ -1,6 +1,6 @@
1
-/*************
2
- * dummy.cpp *
3
- *************/
1
+/***************
2
+ * example.cpp *
3
+ ***************/
4 4
 
5 5
 /****************************************************************************
6 6
  *   Written By Marcio Teixeira 2018 - Aleph Objects, Inc.                  *
@@ -21,7 +21,7 @@
21 21
 
22 22
 #include "../../../inc/MarlinConfigPre.h"
23 23
 
24
-#if ENABLED(EXTENSIBLE_UI)
24
+#if BOTH(EXTUI_EXAMPLE, EXTENSIBLE_UI)
25 25
 
26 26
 #include "../ui_api.h"
27 27
 
@@ -58,8 +58,36 @@ namespace ExtUI {
58 58
   void onUserConfirmRequired(const char * const msg) {}
59 59
   void onStatusChanged(const char * const msg) {}
60 60
   void onFactoryReset() {}
61
-  void onLoadSettings() {}
62
-  void onStoreSettings() {}
61
+
62
+  void onStoreSettings(char *buff) {
63
+    // This is called when saving to EEPROM (i.e. M500). If the ExtUI needs
64
+    // permanent data to be stored, it can write up to eeprom_data_size bytes
65
+    // into buff.
66
+
67
+    // Example:
68
+    //  static_assert(sizeof(myDataStruct) <= ExtUI::eeprom_data_size);
69
+    //  memcpy(buff, &myDataStruct, sizeof(myDataStruct));
70
+  }
71
+
72
+  void onLoadSettings(const char *buff) {
73
+    // This is called while loading settings from EEPROM. If the ExtUI
74
+    // needs to retrieve data, it should copy up to eeprom_data_size bytes
75
+    // from buff
76
+
77
+    // Example:
78
+    //  static_assert(sizeof(myDataStruct) <= ExtUI::eeprom_data_size);
79
+    //  memcpy(&myDataStruct, buff, sizeof(myDataStruct));
80
+  }
81
+
82
+  void onConfigurationStoreWritten(bool success) {
83
+    // This is called after the entire EEPROM has been written,
84
+    // whether successful or not.
85
+  }
86
+
87
+  void onConfigurationStoreRead(bool success) {
88
+    // This is called after the entire EEPROM has been read,
89
+    // whether successful or not.
90
+  }
63 91
 }
64 92
 
65
-#endif // EXTENSIBLE_UI
93
+#endif // EXTUI_EXAMPLE && EXTENSIBLE_UI

+ 11
- 16
Marlin/src/lcd/extensible_ui/ui_api.cpp View File

@@ -82,11 +82,7 @@
82 82
 #include "ui_api.h"
83 83
 
84 84
 #if ENABLED(BACKLASH_GCODE)
85
-  extern float backlash_distance_mm[XYZ];
86
-  extern uint8_t backlash_correction;
87
-  #ifdef BACKLASH_SMOOTHING_MM
88
-    extern float backlash_smoothing_mm;
89
-  #endif
85
+  #include "../../feature/backlash.h"
90 86
 #endif
91 87
 
92 88
 #if HAS_LEVELING
@@ -111,7 +107,6 @@ static struct {
111 107
 } flags;
112 108
 
113 109
 namespace ExtUI {
114
-
115 110
   #ifdef __SAM3X8E__
116 111
     /**
117 112
      * Implement a special millis() to allow time measurement
@@ -517,13 +512,13 @@ namespace ExtUI {
517 512
     bool getFilamentRunoutEnabled()                 { return runout.enabled; }
518 513
     void setFilamentRunoutEnabled(const bool value) { runout.enabled = value; }
519 514
 
520
-    #if FILAMENT_RUNOUT_DISTANCE_MM > 0
515
+    #ifdef FILAMENT_RUNOUT_DISTANCE_MM
521 516
       float getFilamentRunoutDistance_mm() {
522
-        return RunoutResponseDelayed::runout_distance_mm;
517
+        return runout.runout_distance();
523 518
       }
524 519
 
525 520
       void setFilamentRunoutDistance_mm(const float value) {
526
-        RunoutResponseDelayed::runout_distance_mm = clamp(value, 0, 999);
521
+        runout.set_runout_distance(clamp(value, 0, 999));
527 522
       }
528 523
     #endif
529 524
   #endif
@@ -687,16 +682,16 @@ namespace ExtUI {
687 682
   #endif // HAS_HOTEND_OFFSET
688 683
 
689 684
   #if ENABLED(BACKLASH_GCODE)
690
-    float getAxisBacklash_mm(const axis_t axis)       { return backlash_distance_mm[axis]; }
685
+    float getAxisBacklash_mm(const axis_t axis)       { return backlash.distance_mm[axis]; }
691 686
     void setAxisBacklash_mm(const float value, const axis_t axis)
692
-                                                      { backlash_distance_mm[axis] = clamp(value,0,5); }
687
+                                                      { backlash.distance_mm[axis] = clamp(value,0,5); }
693 688
 
694
-    float getBacklashCorrection_percent()             { return ui8_to_percent(backlash_correction); }
695
-    void setBacklashCorrection_percent(const float value) { backlash_correction = map(clamp(value, 0, 100), 0, 100, 0, 255); }
689
+    float getBacklashCorrection_percent()             { return ui8_to_percent(backlash.correction); }
690
+    void setBacklashCorrection_percent(const float value) { backlash.correction = map(clamp(value, 0, 100), 0, 100, 0, 255); }
696 691
 
697 692
     #ifdef BACKLASH_SMOOTHING_MM
698
-      float getBacklashSmoothing_mm()                 { return backlash_smoothing_mm; }
699
-      void setBacklashSmoothing_mm(const float value) { backlash_smoothing_mm = clamp(value, 0, 999); }
693
+      float getBacklashSmoothing_mm()                 { return backlash.smoothing_mm; }
694
+      void setBacklashSmoothing_mm(const float value) { backlash.smoothing_mm = clamp(value, 0, 999); }
700 695
     #endif
701 696
   #endif
702 697
 
@@ -750,7 +745,7 @@ namespace ExtUI {
750 745
   }
751 746
 
752 747
   bool commandsInQueue() { return (planner.movesplanned() || commands_in_queue); }
753
-  
748
+
754 749
   bool isAxisPositionKnown(const axis_t axis) {
755 750
     return TEST(axis_known_position, axis);
756 751
   }

+ 10
- 3
Marlin/src/lcd/extensible_ui/ui_api.h View File

@@ -46,6 +46,11 @@
46 46
 #include "../../inc/MarlinConfig.h"
47 47
 
48 48
 namespace ExtUI {
49
+  // The ExtUI implementation can store up to this many bytes
50
+  // in the EEPROM when the methods onStoreSettings and
51
+  // onLoadSettings are called.
52
+
53
+  static constexpr size_t eeprom_data_size = 48;
49 54
 
50 55
   enum axis_t     : uint8_t { X, Y, Z };
51 56
   enum extruder_t : uint8_t { E0, E1, E2, E3, E4, E5 };
@@ -207,7 +212,7 @@ namespace ExtUI {
207 212
     bool getFilamentRunoutEnabled();
208 213
     void setFilamentRunoutEnabled(const bool);
209 214
 
210
-    #if FILAMENT_RUNOUT_DISTANCE_MM > 0
215
+    #ifdef FILAMENT_RUNOUT_DISTANCE_MM
211 216
       float getFilamentRunoutDistance_mm();
212 217
       void setFilamentRunoutDistance_mm(const float);
213 218
     #endif
@@ -283,8 +288,10 @@ namespace ExtUI {
283 288
   void onUserConfirmRequired(const char * const msg);
284 289
   void onStatusChanged(const char * const msg);
285 290
   void onFactoryReset();
286
-  void onStoreSettings();
287
-  void onLoadSettings();
291
+  void onStoreSettings(char *);
292
+  void onLoadSettings(const char *);
293
+  void onConfigurationStoreWritten(bool success);
294
+  void onConfigurationStoreRead(bool success);
288 295
 };
289 296
 
290 297
 /**

+ 107
- 71
Marlin/src/lcd/malyanlcd.cpp View File

@@ -41,23 +41,19 @@
41 41
  * Copyright (c) 2017 Jason Nelson (xC0000005)
42 42
  */
43 43
 
44
-#include "../inc/MarlinConfig.h"
44
+#include "../inc/MarlinConfigPre.h"
45 45
 
46 46
 #if ENABLED(MALYAN_LCD)
47 47
 
48
+#include "extensible_ui/ui_api.h"
49
+
48 50
 #include "ultralcd.h"
49 51
 #include "../module/temperature.h"
50
-#include "../module/planner.h"
51 52
 #include "../module/stepper.h"
52 53
 #include "../module/motion.h"
53
-#include "../module/probe.h"
54 54
 #include "../libs/duration_t.h"
55 55
 #include "../module/printcounter.h"
56
-#include "../gcode/gcode.h"
57 56
 #include "../gcode/queue.h"
58
-#include "../module/configuration_store.h"
59
-
60
-#include "../Marlin.h"
61 57
 
62 58
 #if ENABLED(SDSUPPORT)
63 59
   #include "../sd/cardreader.h"
@@ -412,78 +408,118 @@ void update_usb_status(const bool forceUpdate) {
412 408
   }
413 409
 }
414 410
 
415
-/**
416
- * - from printer on startup:
417
- * {SYS:STARTED}{VER:29}{SYS:STARTED}{R:UD}
418
- * The optimize attribute fixes a register Compile
419
- * error for amtel.
420
- */
421
-void MarlinUI::update() {
422
-  static char inbound_buffer[MAX_CURLY_COMMAND];
423
-
424
-  // First report USB status.
425
-  update_usb_status(false);
426
-
427
-  // now drain commands...
428
-  while (LCD_SERIAL.available()) {
429
-    const byte b = (byte)LCD_SERIAL.read() & 0x7F;
430
-    inbound_buffer[inbound_count++] = b;
431
-    if (b == '}' || inbound_count == sizeof(inbound_buffer) - 1) {
432
-      inbound_buffer[inbound_count - 1] = '\0';
433
-      process_lcd_command(inbound_buffer);
434
-      inbound_count = 0;
435
-      inbound_buffer[0] = 0;
436
-    }
411
+namespace ExtUI {
412
+  void onStartup() {
413
+    /**
414
+     * The Malyan LCD actually runs as a separate MCU on Serial 1.
415
+     * This code's job is to siphon the weird curly-brace commands from
416
+     * it and translate into gcode, which then gets injected into
417
+     * the command queue where possible.
418
+     */
419
+    inbound_count = 0;
420
+    LCD_SERIAL.begin(500000);
421
+
422
+    // Signal init
423
+    write_to_lcd_P(PSTR("{SYS:STARTED}\r\n"));
424
+
425
+    // send a version that says "unsupported"
426
+    write_to_lcd_P(PSTR("{VER:99}\r\n"));
427
+
428
+    // No idea why it does this twice.
429
+    write_to_lcd_P(PSTR("{SYS:STARTED}\r\n"));
430
+    update_usb_status(true);
437 431
   }
438 432
 
439
-  #if ENABLED(SDSUPPORT)
440
-    // The way last printing status works is simple:
441
-    // The UI needs to see at least one TQ which is not 100%
442
-    // and then when the print is complete, one which is.
443
-    static uint8_t last_percent_done = 100;
444
-
445
-    // If there was a print in progress, we need to emit the final
446
-    // print status as {TQ:100}. Reset last percent done so a new print will
447
-    // issue a percent of 0.
448
-    const uint8_t percent_done = IS_SD_PRINTING() ? card.percentDone() : last_printing_status ? 100 : 0;
449
-    if (percent_done != last_percent_done) {
450
-      char message_buffer[10];
451
-      sprintf_P(message_buffer, PSTR("{TQ:%03i}"), percent_done);
452
-      write_to_lcd(message_buffer);
453
-      last_percent_done = percent_done;
454
-      last_printing_status = IS_SD_PRINTING();
433
+  void onIdle() {
434
+    /**
435
+     * - from printer on startup:
436
+     * {SYS:STARTED}{VER:29}{SYS:STARTED}{R:UD}
437
+     * The optimize attribute fixes a register Compile
438
+     * error for amtel.
439
+     */
440
+    static char inbound_buffer[MAX_CURLY_COMMAND];
441
+
442
+    // First report USB status.
443
+    update_usb_status(false);
444
+
445
+    // now drain commands...
446
+    while (LCD_SERIAL.available()) {
447
+      const byte b = (byte)LCD_SERIAL.read() & 0x7F;
448
+      inbound_buffer[inbound_count++] = b;
449
+      if (b == '}' || inbound_count == sizeof(inbound_buffer) - 1) {
450
+        inbound_buffer[inbound_count - 1] = '\0';
451
+        process_lcd_command(inbound_buffer);
452
+        inbound_count = 0;
453
+        inbound_buffer[0] = 0;
454
+      }
455 455
     }
456
-  #endif
457
-}
458 456
 
459
-/**
460
- * The Malyan LCD actually runs as a separate MCU on Serial 1.
461
- * This code's job is to siphon the weird curly-brace commands from
462
- * it and translate into gcode, which then gets injected into
463
- * the command queue where possible.
464
- */
465
-void MarlinUI::init() {
466
-  inbound_count = 0;
467
-  LCD_SERIAL.begin(500000);
457
+    #if ENABLED(SDSUPPORT)
458
+      // The way last printing status works is simple:
459
+      // The UI needs to see at least one TQ which is not 100%
460
+      // and then when the print is complete, one which is.
461
+      static uint8_t last_percent_done = 100;
462
+
463
+      // If there was a print in progress, we need to emit the final
464
+      // print status as {TQ:100}. Reset last percent done so a new print will
465
+      // issue a percent of 0.
466
+      const uint8_t percent_done = IS_SD_PRINTING() ? card.percentDone() : last_printing_status ? 100 : 0;
467
+      if (percent_done != last_percent_done) {
468
+        char message_buffer[10];
469
+        sprintf_P(message_buffer, PSTR("{TQ:%03i}"), percent_done);
470
+        write_to_lcd(message_buffer);
471
+        last_percent_done = percent_done;
472
+        last_printing_status = IS_SD_PRINTING();
473
+      }
474
+    #endif
475
+  }
468 476
 
469
-  // Signal init
470
-  write_to_lcd_P(PSTR("{SYS:STARTED}\r\n"));
477
+  void onPrinterKilled(PGM_P const msg) {}
478
+  void onMediaInserted() {};
479
+  void onMediaError() {};
480
+  void onMediaRemoved() {};
481
+  void onPlayTone(const uint16_t frequency, const uint16_t duration) {}
482
+  void onPrintTimerStarted() {}
483
+  void onPrintTimerPaused() {}
484
+  void onPrintTimerStopped() {}
485
+  void onFilamentRunout() {}
486
+  void onUserConfirmRequired(const char * const msg) {}
487
+  void onStatusChanged(const char * const msg) {
488
+    write_to_lcd_P(PSTR("{E:"));
489
+    write_to_lcd(msg);
490
+    write_to_lcd_P("}");
491
+  }
492
+  void onFactoryReset() {}
471 493
 
472
-  // send a version that says "unsupported"
473
-  write_to_lcd_P(PSTR("{VER:99}\r\n"));
494
+  void onStoreSettings(char *buff) {
495
+    // This is called when saving to EEPROM (i.e. M500). If the ExtUI needs
496
+    // permanent data to be stored, it can write up to eeprom_data_size bytes
497
+    // into buff.
474 498
 
475
-  // No idea why it does this twice.
476
-  write_to_lcd_P(PSTR("{SYS:STARTED}\r\n"));
477
-  update_usb_status(true);
478
-}
499
+    // Example:
500
+    //  static_assert(sizeof(myDataStruct) <= ExtUI::eeprom_data_size);
501
+    //  memcpy(buff, &myDataStruct, sizeof(myDataStruct));
502
+  }
479 503
 
480
-/**
481
- * Set an alert.
482
- */
483
-void MarlinUI::set_alert_status_P(PGM_P const message) {
484
-  write_to_lcd_P(PSTR("{E:"));
485
-  write_to_lcd_P(message);
486
-  write_to_lcd_P("}");
504
+  void onLoadSettings(const char *buff) {
505
+    // This is called while loading settings from EEPROM. If the ExtUI
506
+    // needs to retrieve data, it should copy up to eeprom_data_size bytes
507
+    // from buff
508
+
509
+    // Example:
510
+    //  static_assert(sizeof(myDataStruct) <= ExtUI::eeprom_data_size);
511
+    //  memcpy(&myDataStruct, buff, sizeof(myDataStruct));
512
+  }
513
+
514
+  void onConfigurationStoreWritten(bool success) {
515
+    // This is called after the entire EEPROM has been written,
516
+    // whether successful or not.
517
+  }
518
+
519
+  void onConfigurationStoreRead(bool success) {
520
+    // This is called after the entire EEPROM has been read,
521
+    // whether successful or not.
522
+  }
487 523
 }
488 524
 
489 525
 #endif // MALYAN_LCD

+ 4
- 9
Marlin/src/lcd/menu/menu_backlash.cpp View File

@@ -30,26 +30,21 @@
30 30
 
31 31
 #include "menu.h"
32 32
 
33
-extern float backlash_distance_mm[XYZ];
34
-extern uint8_t backlash_correction;
35
-
36
-#ifdef BACKLASH_SMOOTHING_MM
37
-  extern float backlash_smoothing_mm;
38
-#endif
33
+#include "../../feature/backlash.h"
39 34
 
40 35
 void menu_backlash() {
41 36
   START_MENU();
42 37
   MENU_BACK(MSG_MAIN);
43 38
 
44
-  MENU_MULTIPLIER_ITEM_EDIT(percent, MSG_BACKLASH_CORRECTION, &backlash_correction, all_off, all_on);
39
+  MENU_MULTIPLIER_ITEM_EDIT(percent, MSG_BACKLASH_CORRECTION, &backlash.correction, all_off, all_on);
45 40
 
46
-  #define EDIT_BACKLASH_DISTANCE(N) MENU_MULTIPLIER_ITEM_EDIT(float43, MSG_##N, &backlash_distance_mm[_AXIS(N)], 0.0f, 9.9f);
41
+  #define EDIT_BACKLASH_DISTANCE(N) MENU_MULTIPLIER_ITEM_EDIT(float43, MSG_##N, &backlash.distance_mm[_AXIS(N)], 0.0f, 9.9f);
47 42
   EDIT_BACKLASH_DISTANCE(A);
48 43
   EDIT_BACKLASH_DISTANCE(B);
49 44
   EDIT_BACKLASH_DISTANCE(C);
50 45
 
51 46
   #ifdef BACKLASH_SMOOTHING_MM
52
-    MENU_MULTIPLIER_ITEM_EDIT(float43, MSG_BACKLASH_SMOOTHING, &backlash_smoothing_mm, 0.0f, 9.9f);
47
+    MENU_MULTIPLIER_ITEM_EDIT(float43, MSG_BACKLASH_SMOOTHING, &backlash.smoothing_mm, 0.0f, 9.9f);
53 48
   #endif
54 49
 
55 50
   END_MENU();

+ 1
- 1
Marlin/src/lcd/ultralcd.cpp View File

@@ -23,7 +23,7 @@
23 23
 #include "../inc/MarlinConfigPre.h"
24 24
 
25 25
 // These displays all share the MarlinUI class
26
-#if HAS_SPI_LCD || EITHER(MALYAN_LCD, EXTENSIBLE_UI)
26
+#if HAS_SPI_LCD || ENABLED(EXTENSIBLE_UI)
27 27
   #include "ultralcd.h"
28 28
   #include "fontutils.h"
29 29
   MarlinUI ui;

+ 173
- 9
Marlin/src/module/configuration_store.cpp View File

@@ -37,7 +37,7 @@
37 37
  */
38 38
 
39 39
 // Change EEPROM version if the structure changes
40
-#define EEPROM_VERSION "V65"
40
+#define EEPROM_VERSION "V66"
41 41
 #define EEPROM_OFFSET 100
42 42
 
43 43
 // Check the integrity of data offsets.
@@ -90,10 +90,16 @@
90 90
 
91 91
 #include "../feature/pause.h"
92 92
 
93
+#if ENABLED(BACKLASH_COMPENSATION)
94
+  #include "../feature/backlash.h"
95
+#endif
96
+
93 97
 #if HAS_FILAMENT_SENSOR
94 98
   #include "../feature/runout.h"
95 99
 #endif
96 100
 
101
+#include "../lcd/extensible_ui/ui_api.h"
102
+
97 103
 #if ENABLED(EXTRA_LIN_ADVANCE_K)
98 104
 extern float saved_extruder_advance_K[EXTRUDERS];
99 105
 #endif
@@ -149,6 +155,7 @@ typedef struct SettingsDataStruct {
149 155
   // FILAMENT_RUNOUT_SENSOR
150 156
   //
151 157
   bool runout_sensor_enabled;                           // M412 S
158
+  float runout_distance_mm;                             // M412 D
152 159
 
153 160
   //
154 161
   // ENABLE_LEVELING_FADE_HEIGHT
@@ -298,6 +305,21 @@ typedef struct SettingsDataStruct {
298 305
     toolchange_settings_t toolchange_settings;          // M217 S P R
299 306
   #endif
300 307
 
308
+  //
309
+  // BACKLASH_COMPENSATION
310
+  //
311
+  float backlash_distance_mm[XYZ];                      // M425 X Y Z
312
+  uint8_t backlash_correction;                          // M425 F
313
+  float backlash_smoothing_mm;                          // M425 S
314
+
315
+  //
316
+  // EXTENSIBLE_UI
317
+  //
318
+  #if ENABLED(EXTENSIBLE_UI)
319
+    // This is a significant hardware change; don't reserve space when not present
320
+    uint8_t extui_data[ExtUI::eeprom_data_size];
321
+  #endif
322
+
301 323
 } SettingsData;
302 324
 
303 325
 //static_assert(sizeof(SettingsData) <= E2END + 1, "EEPROM too small to contain SettingsData!");
@@ -372,6 +394,16 @@ void MarlinSettings::postprocess() {
372 394
     report_current_position();
373 395
 }
374 396
 
397
+#if ENABLED(PRINTCOUNTER) && ENABLED(EEPROM_SETTINGS)
398
+  #include "printcounter.h"
399
+
400
+  static_assert(
401
+    !WITHIN(STATS_EEPROM_ADDRESS, EEPROM_OFFSET, EEPROM_OFFSET + sizeof(SettingsData)) &&
402
+    !WITHIN(STATS_EEPROM_ADDRESS + sizeof(printStatistics), EEPROM_OFFSET, EEPROM_OFFSET + sizeof(SettingsData)),
403
+    "STATS_EEPROM_ADDRESS collides with EEPROM settings storage."
404
+  );
405
+#endif
406
+
375 407
 #if ENABLED(SD_FIRMWARE_UPDATE)
376 408
 
377 409
   #if ENABLED(EEPROM_SETTINGS)
@@ -528,11 +560,18 @@ void MarlinSettings::postprocess() {
528 560
     //
529 561
     {
530 562
       #if HAS_FILAMENT_SENSOR
531
-        EEPROM_WRITE(runout.enabled);
563
+        const bool &runout_sensor_enabled = runout.enabled;
532 564
       #else
533
-        const bool runout_sensor_enabled = true;
534
-        EEPROM_WRITE(runout_sensor_enabled);
565
+        const bool runout_sensor_enabled = false;
535 566
       #endif
567
+      #if HAS_FILAMENT_SENSOR && defined(FILAMENT_RUNOUT_DISTANCE_MM)
568
+        const float &runout_distance_mm = runout.runout_distance();
569
+      #else
570
+        const float runout_distance_mm = 0;
571
+      #endif
572
+      _FIELD_TEST(runout_sensor_enabled);
573
+      EEPROM_WRITE(runout_sensor_enabled);
574
+      EEPROM_WRITE(runout_distance_mm);
536 575
     }
537 576
 
538 577
     //
@@ -1119,6 +1158,42 @@ void MarlinSettings::postprocess() {
1119 1158
     #endif
1120 1159
 
1121 1160
     //
1161
+    // Backlash Compensation
1162
+    //
1163
+    {
1164
+      #if ENABLED(BACKLASH_COMPENSATION)
1165
+        const float   (&backlash_distance_mm)[XYZ] = backlash.distance_mm;
1166
+        const uint8_t &backlash_correction         = backlash.correction;
1167
+      #else
1168
+        const float    backlash_distance_mm[XYZ]   = { 0 };
1169
+        const uint8_t  backlash_correction         = 0;
1170
+      #endif
1171
+      #ifdef BACKLASH_SMOOTHING_MM
1172
+        const float   &backlash_smoothing_mm       = backlash.smoothing_mm;
1173
+      #else
1174
+        const float    backlash_smoothing_mm       = 3;
1175
+      #endif
1176
+      _FIELD_TEST(backlash_distance_mm);
1177
+      EEPROM_WRITE(backlash_distance_mm[X_AXIS]);
1178
+      EEPROM_WRITE(backlash_distance_mm[Y_AXIS]);
1179
+      EEPROM_WRITE(backlash_distance_mm[Z_AXIS]);
1180
+      EEPROM_WRITE(backlash_correction);
1181
+      EEPROM_WRITE(backlash_smoothing_mm);
1182
+    }
1183
+
1184
+    //
1185
+    // Extensible UI User Data
1186
+    //
1187
+    #if ENABLED(EXTENSIBLE_UI)
1188
+      {
1189
+        char extui_data[ExtUI::eeprom_data_size] = { 0 };
1190
+        ExtUI::onStoreSettings(extui_data);
1191
+        _FIELD_TEST(extui_data);
1192
+        EEPROM_WRITE(extui_data);
1193
+      }
1194
+    #endif
1195
+
1196
+    //
1122 1197
     // Validate CRC and Data Size
1123 1198
     //
1124 1199
     if (!eeprom_error) {
@@ -1148,7 +1223,7 @@ void MarlinSettings::postprocess() {
1148 1223
     #endif
1149 1224
 
1150 1225
     #if ENABLED(EXTENSIBLE_UI)
1151
-      if (!eeprom_error) ExtUI::onStoreSettings();
1226
+      ExtUI::onConfigurationStoreWritten(!eeprom_error);
1152 1227
     #endif
1153 1228
 
1154 1229
     return !eeprom_error;
@@ -1264,12 +1339,18 @@ void MarlinSettings::postprocess() {
1264 1339
       // Filament Runout Sensor
1265 1340
       //
1266 1341
       {
1267
-        _FIELD_TEST(runout_sensor_enabled);
1268 1342
         #if HAS_FILAMENT_SENSOR
1269
-          EEPROM_READ(runout.enabled);
1343
+          bool &runout_sensor_enabled = runout.enabled;
1270 1344
         #else
1271 1345
           bool runout_sensor_enabled;
1272
-          EEPROM_READ(runout_sensor_enabled);
1346
+        #endif
1347
+        _FIELD_TEST(runout_sensor_enabled);
1348
+        EEPROM_READ(runout_sensor_enabled);
1349
+
1350
+        float runout_distance_mm;
1351
+        EEPROM_READ(runout_distance_mm);
1352
+        #if HAS_FILAMENT_SENSOR && defined(FILAMENT_RUNOUT_DISTANCE_MM)
1353
+          runout.set_runout_distance(runout_distance_mm);
1273 1354
         #endif
1274 1355
       }
1275 1356
 
@@ -1851,6 +1932,44 @@ void MarlinSettings::postprocess() {
1851 1932
         EEPROM_READ(toolchange_settings);
1852 1933
       #endif
1853 1934
 
1935
+      //
1936
+      // Backlash Compensation
1937
+      //
1938
+      {
1939
+        #if ENABLED(BACKLASH_COMPENSATION)
1940
+          float   (&backlash_distance_mm)[XYZ] = backlash.distance_mm;
1941
+          uint8_t &backlash_correction         = backlash.correction;
1942
+        #else
1943
+          float   backlash_distance_mm[XYZ];
1944
+          uint8_t backlash_correction;
1945
+        #endif
1946
+        #ifdef BACKLASH_SMOOTHING_MM
1947
+          float &backlash_smoothing_mm = backlash.smoothing_mm;
1948
+        #else
1949
+          float  backlash_smoothing_mm;
1950
+        #endif
1951
+        _FIELD_TEST(backlash_distance_mm);
1952
+        EEPROM_READ(backlash_distance_mm[X_AXIS]);
1953
+        EEPROM_READ(backlash_distance_mm[Y_AXIS]);
1954
+        EEPROM_READ(backlash_distance_mm[Z_AXIS]);
1955
+        EEPROM_READ(backlash_correction);
1956
+        EEPROM_READ(backlash_smoothing_mm);
1957
+      }
1958
+
1959
+      //
1960
+      // Extensible UI User Data
1961
+      //
1962
+      #if ENABLED(EXTENSIBLE_UI)
1963
+        // This is a significant hardware change; don't reserve EEPROM space when not present
1964
+        {
1965
+          const char extui_data[ExtUI::eeprom_data_size] = { 0 };
1966
+          _FIELD_TEST(extui_data);
1967
+          EEPROM_READ(extui_data);
1968
+          if(!validating)
1969
+            ExtUI::onLoadSettings(extui_data);
1970
+        }
1971
+      #endif
1972
+
1854 1973
       eeprom_error = size_error(eeprom_index - (EEPROM_OFFSET));
1855 1974
       if (eeprom_error) {
1856 1975
         DEBUG_ECHO_START();
@@ -1921,7 +2040,7 @@ void MarlinSettings::postprocess() {
1921 2040
     if (validate()) {
1922 2041
       const bool success = _load();
1923 2042
       #if ENABLED(EXTENSIBLE_UI)
1924
-        if (success) ExtUI::onLoadSettings();
2043
+        ExtUI::onConfigurationStoreRead(success);
1925 2044
       #endif
1926 2045
       return success;
1927 2046
     }
@@ -2090,6 +2209,9 @@ void MarlinSettings::reset() {
2090 2209
   #if HAS_FILAMENT_SENSOR
2091 2210
     runout.enabled = true;
2092 2211
     runout.reset();
2212
+    #ifdef FILAMENT_RUNOUT_DISTANCE_MM
2213
+      runout.set_runout_distance(FILAMENT_RUNOUT_DISTANCE_MM);
2214
+    #endif
2093 2215
   #endif
2094 2216
 
2095 2217
   //
@@ -2108,6 +2230,23 @@ void MarlinSettings::reset() {
2108 2230
     toolchange_settings.z_raise = TOOLCHANGE_ZRAISE;
2109 2231
   #endif
2110 2232
 
2233
+  #if ENABLED(BACKLASH_GCODE)
2234
+    backlash.correction = (BACKLASH_CORRECTION) * 255;
2235
+    #ifdef BACKLASH_DISTANCE_MM
2236
+      constexpr float tmp[XYZ] = BACKLASH_DISTANCE_MM;
2237
+      backlash.distance_mm[X_AXIS] = tmp[X_AXIS];
2238
+      backlash.distance_mm[Y_AXIS] = tmp[Y_AXIS];
2239
+      backlash.distance_mm[Z_AXIS] = tmp[Z_AXIS];
2240
+    #endif
2241
+    #ifdef BACKLASH_SMOOTHING_MM
2242
+      backlash.smoothing_mm = BACKLASH_SMOOTHING_MM;
2243
+    #endif
2244
+  #endif
2245
+
2246
+  #if ENABLED(EXTENSIBLE_UI)
2247
+    ExtUI::onFactoryReset();
2248
+  #endif
2249
+
2111 2250
   //
2112 2251
   // Magnetic Parking Extruder
2113 2252
   //
@@ -3200,6 +3339,31 @@ void MarlinSettings::reset() {
3200 3339
       CONFIG_ECHO_START();
3201 3340
       M217_report(true);
3202 3341
     #endif
3342
+
3343
+    #if ENABLED(BACKLASH_GCODE)
3344
+      CONFIG_ECHO_HEADING("Backlash compensation:");
3345
+      CONFIG_ECHO_START();
3346
+      SERIAL_ECHOLNPAIR(
3347
+        "  M425 F", backlash.get_correction(),
3348
+        " X", LINEAR_UNIT(backlash.distance_mm[X_AXIS]),
3349
+        " Y", LINEAR_UNIT(backlash.distance_mm[Y_AXIS]),
3350
+        " Z", LINEAR_UNIT(backlash.distance_mm[Z_AXIS])
3351
+        #ifdef BACKLASH_SMOOTHING_MM
3352
+          , " S", LINEAR_UNIT(backlash.smoothing_mm)
3353
+        #endif
3354
+      );
3355
+    #endif
3356
+
3357
+    #if HAS_FILAMENT_SENSOR
3358
+      CONFIG_ECHO_HEADING("Filament runout sensor:");
3359
+      CONFIG_ECHO_START();
3360
+      SERIAL_ECHOLNPAIR(
3361
+        "  M412 S", int(runout.enabled)
3362
+        #ifdef FILAMENT_RUNOUT_DISTANCE_MM
3363
+          , " D", LINEAR_UNIT(runout.runout_distance())
3364
+        #endif
3365
+      );
3366
+    #endif
3203 3367
   }
3204 3368
 
3205 3369
 #endif // !DISABLE_M503

+ 5
- 89
Marlin/src/module/planner.cpp View File

@@ -92,6 +92,10 @@
92 92
   #include "../feature/power.h"
93 93
 #endif
94 94
 
95
+#if ENABLED(BACKLASH_COMPENSATION)
96
+  #include "../feature/backlash.h"
97
+#endif
98
+
95 99
 // Delay for delivery of first block to the stepper ISR, if the queue contains 2 or
96 100
 // fewer movements. The delay is measured in milliseconds, and must be less than 250ms
97 101
 #define BLOCK_DELAY_FOR_1ST_MOVE 100
@@ -1561,94 +1565,6 @@ void Planner::synchronize() {
1561 1565
 }
1562 1566
 
1563 1567
 /**
1564
- * The following implements axis backlash correction. To minimize seams
1565
- * on the printed part, the backlash correction only adds steps to the
1566
- * current segment (instead of creating a new segment, which causes
1567
- * discontinuities and print artifacts).
1568
- *
1569
- * When BACKLASH_SMOOTHING_MM is enabled and non-zero, the backlash
1570
- * correction is spread over multiple segments, smoothing out print
1571
- * artifacts even more.
1572
- */
1573
-#if ENABLED(BACKLASH_COMPENSATION)
1574
-  #if ENABLED(BACKLASH_GCODE)
1575
-    extern float backlash_distance_mm[];
1576
-    extern uint8_t backlash_correction;
1577
-    #ifdef BACKLASH_SMOOTHING_MM
1578
-      extern float backlash_smoothing_mm;
1579
-    #endif
1580
-  #else
1581
-    constexpr float backlash_distance_mm[XYZ] = BACKLASH_DISTANCE_MM,
1582
-    constexpr uint8_t backlash_correction = BACKLASH_CORRECTION * 255;
1583
-    #ifdef BACKLASH_SMOOTHING_MM
1584
-      constexpr float backlash_smoothing_mm = BACKLASH_SMOOTHING_MM;
1585
-    #endif
1586
-  #endif
1587
-
1588
-  void Planner::add_backlash_correction_steps(const int32_t da, const int32_t db, const int32_t dc, const uint8_t dm, block_t * const block) {
1589
-    static uint8_t last_direction_bits;
1590
-    uint8_t changed_dir = last_direction_bits ^ dm;
1591
-    // Ignore direction change if no steps are taken in that direction
1592
-    if (da == 0) CBI(changed_dir, X_AXIS);
1593
-    if (db == 0) CBI(changed_dir, Y_AXIS);
1594
-    if (dc == 0) CBI(changed_dir, Z_AXIS);
1595
-    last_direction_bits ^= changed_dir;
1596
-
1597
-    if (backlash_correction == 0) return;
1598
-
1599
-    #ifdef BACKLASH_SMOOTHING_MM
1600
-      // The segment proportion is a value greater than 0.0 indicating how much residual_error
1601
-      // is corrected for in this segment. The contribution is based on segment length and the
1602
-      // smoothing distance. Since the computation of this proportion involves a floating point
1603
-      // division, defer computation until needed.
1604
-      float segment_proportion = 0;
1605
-
1606
-      // Residual error carried forward across multiple segments, so correction can be applied
1607
-      // to segments where there is no direction change.
1608
-      static int32_t residual_error[XYZ] = { 0 };
1609
-    #else
1610
-      // No leftover residual error from segment to segment
1611
-      int32_t residual_error[XYZ] = { 0 };
1612
-      // No direction change, no correction.
1613
-      if (!changed_dir) return;
1614
-    #endif
1615
-
1616
-    const float f_corr = float(backlash_correction) / 255.0f;
1617
-
1618
-    LOOP_XYZ(axis) {
1619
-      if (backlash_distance_mm[axis]) {
1620
-        const bool reversing = TEST(dm,axis);
1621
-
1622
-        // When an axis changes direction, add axis backlash to the residual error
1623
-        if (TEST(changed_dir, axis))
1624
-          residual_error[axis] += (reversing ? -f_corr : f_corr) * backlash_distance_mm[axis] * planner.settings.axis_steps_per_mm[axis];
1625
-
1626
-        // Decide how much of the residual error to correct in this segment
1627
-        int32_t error_correction = residual_error[axis];
1628
-        #ifdef BACKLASH_SMOOTHING_MM
1629
-          if (error_correction && backlash_smoothing_mm != 0) {
1630
-            // Take up a portion of the residual_error in this segment, but only when
1631
-            // the current segment travels in the same direction as the correction
1632
-            if (reversing == (error_correction < 0)) {
1633
-              if (segment_proportion == 0)
1634
-                segment_proportion = MIN(1.0f, block->millimeters / backlash_smoothing_mm);
1635
-              error_correction = ceil(segment_proportion * error_correction);
1636
-            }
1637
-            else
1638
-              error_correction = 0; // Don't take up any backlash in this segment, as it would subtract steps
1639
-          }
1640
-        #endif
1641
-        // Making a correction reduces the residual error and modifies delta_mm
1642
-        if (error_correction) {
1643
-          block->steps[axis] += ABS(error_correction);
1644
-          residual_error[axis] -= error_correction;
1645
-        }
1646
-      }
1647
-    }
1648
-  }
1649
-#endif // BACKLASH_COMPENSATION
1650
-
1651
-/**
1652 1568
  * Planner::_buffer_steps
1653 1569
  *
1654 1570
  * Add a new linear movement to the planner queue (in terms of steps).
@@ -1919,7 +1835,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
1919 1835
      * should *never* remove steps!
1920 1836
      */
1921 1837
     #if ENABLED(BACKLASH_COMPENSATION)
1922
-      add_backlash_correction_steps(da, db, dc, dm, block);
1838
+      backlash.add_correction_steps(da, db, dc, dm, block);
1923 1839
     #endif
1924 1840
   }
1925 1841
 

+ 0
- 4
Marlin/src/module/planner.h View File

@@ -338,10 +338,6 @@ class Planner {
338 338
       volatile static uint32_t block_buffer_runtime_us; //Theoretical block buffer runtime in µs
339 339
     #endif
340 340
 
341
-    #if ENABLED(BACKLASH_COMPENSATION)
342
-      static void add_backlash_correction_steps(const int32_t da, const int32_t db, const int32_t dc, const uint8_t dm, block_t * const block);
343
-    #endif
344
-
345 341
   public:
346 342
 
347 343
     /**

+ 8
- 0
Marlin/src/module/printcounter.cpp View File

@@ -29,6 +29,10 @@ Stopwatch print_job_timer;      // Global Print Job Timer instance
29 29
 
30 30
 #else // PRINTCOUNTER
31 31
 
32
+#if ENABLED(EXTENSIBLE_UI)
33
+  #include "../lcd/extensible_ui/ui_api.h"
34
+#endif
35
+
32 36
 #include "printcounter.h"
33 37
 #include "../Marlin.h"
34 38
 #include "../HAL/shared/persistent_store_api.h"
@@ -169,6 +173,10 @@ void PrintCounter::saveStats() {
169 173
   persistentStore.access_start();
170 174
   persistentStore.write_data(address + sizeof(uint8_t), (uint8_t*)&data, sizeof(printStatistics));
171 175
   persistentStore.access_finish();
176
+
177
+  #if ENABLED(EXTENSIBLE_UI)
178
+    ExtUI::onConfigurationStoreWritten(true);
179
+  #endif
172 180
 }
173 181
 
174 182
 #if HAS_SERVICE_INTERVALS

+ 5
- 25
Marlin/src/module/probe.cpp View File

@@ -54,6 +54,10 @@
54 54
   #include "planner.h"
55 55
 #endif
56 56
 
57
+#if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
58
+  #include "../feature/backlash.h"
59
+#endif
60
+
57 61
 float zprobe_zoffset; // Initialized by settings.load()
58 62
 
59 63
 #if ENABLED(BLTOUCH)
@@ -463,30 +467,6 @@ bool set_probe_deployed(const bool deploy) {
463 467
   }
464 468
 #endif
465 469
 
466
-#if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
467
-  #if USES_Z_MIN_PROBE_ENDSTOP
468
-    #define TEST_PROBE_PIN (READ(Z_MIN_PROBE_PIN) != Z_MIN_PROBE_ENDSTOP_INVERTING)
469
-  #else
470
-    #define TEST_PROBE_PIN (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING)
471
-  #endif
472
-
473
-  extern float backlash_measured_mm[];
474
-  extern uint8_t backlash_measured_num[];
475
-
476
-  /* Measure Z backlash by raising nozzle in increments until probe deactivates */
477
-  static void measure_backlash_with_probe() {
478
-    if (backlash_measured_num[Z_AXIS] == 255) return;
479
-
480
-    float start_height = current_position[Z_AXIS];
481
-    while (current_position[Z_AXIS] < (start_height + BACKLASH_MEASUREMENT_LIMIT) && TEST_PROBE_PIN)
482
-      do_blocking_move_to_z(current_position[Z_AXIS] + BACKLASH_MEASUREMENT_RESOLUTION, MMM_TO_MMS(BACKLASH_MEASUREMENT_FEEDRATE));
483
-
484
-    // The backlash from all probe points is averaged, so count the number of measurements
485
-    backlash_measured_mm[Z_AXIS] += current_position[Z_AXIS] - start_height;
486
-    backlash_measured_num[Z_AXIS]++;
487
-  }
488
-#endif
489
-
490 470
 /**
491 471
  * @brief Used by run_z_probe to do a single Z probe move.
492 472
  *
@@ -643,7 +623,7 @@ static float run_z_probe() {
643 623
       }
644 624
 
645 625
       #if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
646
-        measure_backlash_with_probe();
626
+        backlash.measure_with_probe();
647 627
       #endif
648 628
 
649 629
   #if MULTIPLE_PROBING > 2

+ 2
- 2
Marlin/src/module/stepper.cpp View File

@@ -113,7 +113,7 @@ Stepper stepper; // Singleton
113 113
   #include "../feature/mixing.h"
114 114
 #endif
115 115
 
116
-#if FILAMENT_RUNOUT_DISTANCE_MM > 0
116
+#ifdef FILAMENT_RUNOUT_DISTANCE_MM
117 117
   #include "../feature/runout.h"
118 118
 #endif
119 119
 
@@ -1537,7 +1537,7 @@ uint32_t Stepper::stepper_block_phase_isr() {
1537 1537
 
1538 1538
     // If current block is finished, reset pointer
1539 1539
     if (step_events_completed >= step_event_count) {
1540
-      #if FILAMENT_RUNOUT_DISTANCE_MM > 0
1540
+      #ifdef FILAMENT_RUNOUT_DISTANCE_MM
1541 1541
         runout.block_completed(current_block);
1542 1542
       #endif
1543 1543
       axis_did_move = 0;

Loading…
Cancel
Save