Subversion Repositories Tronxy-X3A-Marlin

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 ron 1
/**
2
 * Marlin 3D Printer Firmware
3
 * Copyright (C) 2016 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
/**
24
 * configuration_store.cpp
25
 *
26
 * Settings and EEPROM storage
27
 *
28
 * IMPORTANT:  Whenever there are changes made to the variables stored in EEPROM
29
 * in the functions below, also increment the version number. This makes sure that
30
 * the default values are used whenever there is a change to the data, to prevent
31
 * wrong data being written to the variables.
32
 *
33
 * ALSO: Variables in the Store and Retrieve sections must be in the same order.
34
 *       If a feature is disabled, some data must still be written that, when read,
35
 *       either sets a Sane Default, or results in No Change to the existing value.
36
 *
37
 */
38
 
39
// Change EEPROM version if the structure changes
40
#define EEPROM_VERSION "V56"
41
#define EEPROM_OFFSET 100
42
 
43
// Check the integrity of data offsets.
44
// Can be disabled for production build.
45
//#define DEBUG_EEPROM_READWRITE
46
 
47
#include "configuration_store.h"
48
#include "Marlin.h"
49
#include "language.h"
50
#include "endstops.h"
51
#include "planner.h"
52
#include "temperature.h"
53
#include "ultralcd.h"
54
#include "stepper.h"
55
#include "parser.h"
56
#include "vector_3.h"
57
 
58
#if ENABLED(MESH_BED_LEVELING)
59
  #include "mesh_bed_leveling.h"
60
#endif
61
 
62
#if HAS_TRINAMIC
63
  #include "stepper_indirection.h"
64
  #include "tmc_util.h"
65
  #define TMC_GET_PWMTHRS(A,Q) _tmc_thrs(stepper##Q.microsteps(), stepper##Q.TPWMTHRS(), planner.axis_steps_per_mm[_AXIS(A)])
66
#endif
67
 
68
#if ENABLED(AUTO_BED_LEVELING_UBL)
69
  #include "ubl.h"
70
#endif
71
 
72
#if ENABLED(FWRETRACT)
73
  #include "fwretract.h"
74
#endif
75
 
76
#if ENABLED(PID_EXTRUSION_SCALING)
77
  #define LPQ_LEN thermalManager.lpq_len
78
#endif
79
 
80
#if ENABLED(BLTOUCH)
81
  extern bool bltouch_last_written_mode;
82
#endif
83
 
84
#pragma pack(push, 1) // No padding between variables
85
 
86
typedef struct PID { float Kp, Ki, Kd; } PID;
87
typedef struct PIDC { float Kp, Ki, Kd, Kc; } PIDC;
88
 
89
/**
90
 * Current EEPROM Layout
91
 *
92
 * Keep this data structure up to date so
93
 * EEPROM size is known at compile time!
94
 */
95
typedef struct SettingsDataStruct {
96
  char      version[4];                                 // Vnn\0
97
  uint16_t  crc;                                        // Data Checksum
98
 
99
  //
100
  // DISTINCT_E_FACTORS
101
  //
102
  uint8_t   esteppers;                                      // NUM_AXIS_N - MOV_AXIS
103
 
104
  uint32_t  planner_max_acceleration_mm_per_s2[NUM_AXIS_N], // M201 XYZE/ABCDE  planner.max_acceleration_mm_per_s2[NUM_AXIS_N]
105
            planner_min_segment_time_us;                    // M205 Q           planner.min_segment_time_us
106
  float     planner_axis_steps_per_mm[NUM_AXIS_N],          // M92 XYZE/ABCDE   planner.axis_steps_per_mm[NUM_AXIS_N]
107
            planner_max_feedrate_mm_s[NUM_AXIS_N],          // M203 XYZE/ABCDE  planner.max_feedrate_mm_s[NUM_AXIS_N]
108
            planner_acceleration,                           // M204 P           planner.acceleration
109
            planner_retract_acceleration,                   // M204 R           planner.retract_acceleration
110
            planner_travel_acceleration,                    // M204 T           planner.travel_acceleration
111
            planner_min_feedrate_mm_s,                      // M205 S           planner.min_feedrate_mm_s
112
            planner_min_travel_feedrate_mm_s,               // M205 T           planner.min_travel_feedrate_mm_s
113
            planner_max_jerk[NUM_AXIS],                     // M205 XYZE/ABCDE  planner.max_jerk[NUM_AXIS]
114
            planner_junction_deviation_mm;                  // M205 J           planner.junction_deviation_mm
115
 
116
  float home_offset[XYZ];                               // M206 XYZ
117
 
118
  #if HOTENDS > 1
119
    float hotend_offset[XYZ][HOTENDS - 1];              // M218 XYZ
120
  #endif
121
 
122
  //
123
  // ENABLE_LEVELING_FADE_HEIGHT
124
  //
125
  float planner_z_fade_height;                          // M420 Zn  planner.z_fade_height
126
 
127
  //
128
  // MESH_BED_LEVELING
129
  //
130
  float mbl_z_offset;                                   // mbl.z_offset
131
  uint8_t mesh_num_x, mesh_num_y;                       // GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y
132
  #if ENABLED(MESH_BED_LEVELING)
133
    float mbl_z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y]; // mbl.z_values
134
  #else
135
    float mbl_z_values[3][3];
136
  #endif
137
 
138
  //
139
  // HAS_BED_PROBE
140
  //
141
  float zprobe_zoffset;                                 // M851 Z
142
 
143
  //
144
  // ABL_PLANAR
145
  //
146
  matrix_3x3 planner_bed_level_matrix;                  // planner.bed_level_matrix
147
 
148
  //
149
  // AUTO_BED_LEVELING_BILINEAR
150
  //
151
  uint8_t grid_max_x, grid_max_y;                       // GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y
152
  int bilinear_grid_spacing[2],
153
      bilinear_start[2];                                // G29 L F
154
  #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
155
    float z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y]; // G29
156
  #else
157
    float z_values[3][3];
158
  #endif
159
 
160
  //
161
  // AUTO_BED_LEVELING_UBL
162
  //
163
  bool planner_leveling_active;                         // M420 S  planner.leveling_active
164
  int8_t ubl_storage_slot;                              // ubl.storage_slot
165
 
166
  //
167
  // BLTOUCH
168
  //
169
  bool bltouch_last_written_mode;
170
 
171
  //
172
  // DELTA / [XYZ]_DUAL_ENDSTOPS
173
  //
174
  #if ENABLED(DELTA)
175
 
176
    float delta_height,                                 // M666 H
177
          delta_endstop_adj[ABC],                       // M666 XYZ
178
          delta_radius,                                 // M665 R
179
          delta_diagonal_rod,                           // M665 L
180
          delta_segments_per_second,                    // M665 S
181
          delta_calibration_radius,                     // M665 B
182
          delta_tower_angle_trim[ABC];                  // M665 XYZ
183
 
184
  #elif ENABLED(HANGPRINTER)
185
 
186
    float anchor_A_y,                                   // M665 W
187
          anchor_A_z,                                   // M665 E
188
          anchor_B_x,                                   // M665 R
189
          anchor_B_y,                                   // M665 T
190
          anchor_B_z,                                   // M665 Y
191
          anchor_C_x,                                   // M665 U
192
          anchor_C_y,                                   // M665 I
193
          anchor_C_z,                                   // M665 O
194
          anchor_D_z,                                   // M665 P
195
          delta_segments_per_second,                    // M665 S
196
          hangprinter_calibration_radius_placeholder;
197
 
198
  #elif ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
199
 
200
    float x_endstop_adj,                                // M666 X
201
          y_endstop_adj,                                // M666 Y
202
          z_endstop_adj;                                // M666 Z
203
 
204
  #endif
205
 
206
  //
207
  // ULTIPANEL
208
  //
209
  int16_t lcd_preheat_hotend_temp[2],                   // M145 S0 H
210
          lcd_preheat_bed_temp[2],                      // M145 S0 B
211
          lcd_preheat_fan_speed[2];                     // M145 S0 F
212
 
213
  //
214
  // PIDTEMP
215
  //
216
  PIDC hotendPID[MAX_EXTRUDERS];                        // M301 En PIDC / M303 En U
217
 
218
  int16_t lpq_len;                                      // M301 L
219
 
220
  //
221
  // PIDTEMPBED
222
  //
223
  PID bedPID;                                           // M304 PID / M303 E-1 U
224
 
225
  //
226
  // HAS_LCD_CONTRAST
227
  //
228
  int16_t lcd_contrast;                                // M250 C
229
 
230
  //
231
  // FWRETRACT
232
  //
233
  bool autoretract_enabled;                             // M209 S
234
  float retract_length,                                 // M207 S
235
        retract_feedrate_mm_s,                          // M207 F
236
        retract_zlift,                                  // M207 Z
237
        retract_recover_length,                         // M208 S
238
        retract_recover_feedrate_mm_s,                  // M208 F
239
        swap_retract_length,                            // M207 W
240
        swap_retract_recover_length,                    // M208 W
241
        swap_retract_recover_feedrate_mm_s;             // M208 R
242
 
243
  //
244
  // !NO_VOLUMETRIC
245
  //
246
  bool parser_volumetric_enabled;                       // M200 D  parser.volumetric_enabled
247
  float planner_filament_size[MAX_EXTRUDERS];           // M200 T D  planner.filament_size[]
248
 
249
  //
250
  // HAS_TRINAMIC
251
  //
252
  #define TMC_AXES (MAX_EXTRUDERS + 6)
253
  uint16_t tmc_stepper_current[TMC_AXES];               // M906 X Y Z X2 Y2 Z2 E0 E1 E2 E3 E4
254
  uint32_t tmc_hybrid_threshold[TMC_AXES];              // M913 X Y Z X2 Y2 Z2 E0 E1 E2 E3 E4
255
  int16_t tmc_sgt[XYZ];                                 // M914 X Y Z
256
 
257
  //
258
  // LIN_ADVANCE
259
  //
260
  float planner_extruder_advance_K;                     // M900 K    planner.extruder_advance_K
261
 
262
  //
263
  // HAS_MOTOR_CURRENT_PWM
264
  //
265
  uint32_t motor_current_setting[XYZ];                  // M907 X Z E
266
 
267
  //
268
  // CNC_COORDINATE_SYSTEMS
269
  //
270
  float coordinate_system[MAX_COORDINATE_SYSTEMS][XYZ]; // G54-G59.3
271
 
272
  //
273
  // SKEW_CORRECTION
274
  //
275
  float planner_xy_skew_factor,                         // M852 I  planner.xy_skew_factor
276
        planner_xz_skew_factor,                         // M852 J  planner.xz_skew_factor
277
        planner_yz_skew_factor;                         // M852 K  planner.yz_skew_factor
278
 
279
  //
280
  // ADVANCED_PAUSE_FEATURE
281
  //
282
  float filament_change_unload_length[MAX_EXTRUDERS],   // M603 T U
283
        filament_change_load_length[MAX_EXTRUDERS];     // M603 T L
284
 
285
} SettingsData;
286
 
287
#pragma pack(pop)
288
 
289
MarlinSettings settings;
290
 
291
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
292
  extern void refresh_bed_level();
293
#endif
294
 
295
uint16_t MarlinSettings::datasize() { return sizeof(SettingsData); }
296
 
297
/**
298
 * Post-process after Retrieve or Reset
299
 */
300
 
301
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
302
  float new_z_fade_height;
303
#endif
304
 
305
void MarlinSettings::postprocess() {
306
  const float oldpos[] = { current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] };
307
 
308
  // steps per s2 needs to be updated to agree with units per s2
309
  planner.reset_acceleration_rates();
310
 
311
  // Make sure delta kinematics are updated before refreshing the
312
  // planner position so the stepper counts will be set correctly.
313
  #if ENABLED(DELTA)
314
    recalc_delta_settings();
315
  #elif ENABLED(HANGPRINTER)
316
    recalc_hangprinter_settings();
317
  #endif
318
 
319
  #if ENABLED(PIDTEMP)
320
    thermalManager.update_pid();
321
  #endif
322
 
323
  #if DISABLED(NO_VOLUMETRICS)
324
    planner.calculate_volumetric_multipliers();
325
  #else
326
    for (uint8_t i = COUNT(planner.e_factor); i--;)
327
      planner.refresh_e_factor(i);
328
  #endif
329
 
330
  #if HAS_HOME_OFFSET || ENABLED(DUAL_X_CARRIAGE)
331
    // Software endstops depend on home_offset
332
    LOOP_XYZ(i) update_software_endstops((AxisEnum)i);
333
  #endif
334
 
335
  #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
336
    set_z_fade_height(new_z_fade_height, false); // false = no report
337
  #endif
338
 
339
  #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
340
    refresh_bed_level();
341
  #endif
342
 
343
  #if HAS_MOTOR_CURRENT_PWM
344
    stepper.refresh_motor_power();
345
  #endif
346
 
347
  #if ENABLED(FWRETRACT)
348
    fwretract.refresh_autoretract();
349
  #endif
350
 
351
  #if ENABLED(JUNCTION_DEVIATION) && ENABLED(LIN_ADVANCE)
352
    planner.recalculate_max_e_jerk();
353
  #endif
354
 
355
  // Refresh steps_to_mm with the reciprocal of axis_steps_per_mm
356
  // and init stepper.count[], planner.position[] with current_position
357
  planner.refresh_positioning();
358
 
359
  // Various factors can change the current position
360
  if (memcmp(oldpos, current_position, sizeof(oldpos)))
361
    report_current_position();
362
}
363
 
364
#if ENABLED(EEPROM_SETTINGS)
365
 
366
  #define EEPROM_START() int eeprom_index = EEPROM_OFFSET
367
  #define EEPROM_SKIP(VAR) eeprom_index += sizeof(VAR)
368
  #define EEPROM_WRITE(VAR) write_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR), &working_crc)
369
  #define EEPROM_READ(VAR) read_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR), &working_crc)
370
  #define EEPROM_READ_ALWAYS(VAR) read_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR), &working_crc, true)
371
  #define EEPROM_ASSERT(TST,ERR) if (!(TST)) do{ SERIAL_ERROR_START(); SERIAL_ERRORLNPGM(ERR); eeprom_error = true; }while(0)
372
 
373
  #if ENABLED(DEBUG_EEPROM_READWRITE)
374
    #define _FIELD_TEST(FIELD) \
375
      EEPROM_ASSERT( \
376
        eeprom_error || eeprom_index == offsetof(SettingsData, FIELD) + EEPROM_OFFSET, \
377
        "Field " STRINGIFY(FIELD) " mismatch." \
378
      )
379
  #else
380
    #define _FIELD_TEST(FIELD) NOOP
381
  #endif
382
 
383
  const char version[4] = EEPROM_VERSION;
384
 
385
  bool MarlinSettings::eeprom_error, MarlinSettings::validating;
386
 
387
  void MarlinSettings::write_data(int &pos, const uint8_t *value, uint16_t size, uint16_t *crc) {
388
    if (eeprom_error) { pos += size; return; }
389
    while (size--) {
390
      uint8_t * const p = (uint8_t * const)pos;
391
      uint8_t v = *value;
392
      // EEPROM has only ~100,000 write cycles,
393
      // so only write bytes that have changed!
394
      if (v != eeprom_read_byte(p)) {
395
        eeprom_write_byte(p, v);
396
        if (eeprom_read_byte(p) != v) {
397
          SERIAL_ECHO_START();
398
          SERIAL_ECHOLNPGM(MSG_ERR_EEPROM_WRITE);
399
          eeprom_error = true;
400
          return;
401
        }
402
      }
403
      crc16(crc, &v, 1);
404
      pos++;
405
      value++;
406
    };
407
  }
408
 
409
  void MarlinSettings::read_data(int &pos, uint8_t* value, uint16_t size, uint16_t *crc, const bool force/*=false*/) {
410
    if (eeprom_error) { pos += size; return; }
411
    do {
412
      uint8_t c = eeprom_read_byte((unsigned char*)pos);
413
      if (!validating || force) *value = c;
414
      crc16(crc, &c, 1);
415
      pos++;
416
      value++;
417
    } while (--size);
418
  }
419
 
420
  bool MarlinSettings::size_error(const uint16_t size) {
421
    if (size != datasize()) {
422
      SERIAL_ERROR_START();
423
      SERIAL_ERRORLNPGM("EEPROM datasize error.");
424
      return true;
425
    }
426
    return false;
427
  }
428
 
429
  /**
430
   * M500 - Store Configuration
431
   */
432
  bool MarlinSettings::save() {
433
    float dummy = 0;
434
    char ver[4] = "ERR";
435
 
436
    uint16_t working_crc = 0;
437
 
438
    EEPROM_START();
439
 
440
    eeprom_error = false;
441
 
442
    EEPROM_WRITE(ver);     // invalidate data first
443
    EEPROM_SKIP(working_crc); // Skip the checksum slot
444
 
445
    working_crc = 0; // clear before first "real data"
446
 
447
    _FIELD_TEST(esteppers);
448
 
449
    const uint8_t esteppers = NUM_AXIS_N - MOV_AXIS;
450
    EEPROM_WRITE(esteppers);
451
 
452
    EEPROM_WRITE(planner.max_acceleration_mm_per_s2);
453
    EEPROM_WRITE(planner.min_segment_time_us);
454
    EEPROM_WRITE(planner.axis_steps_per_mm);
455
    EEPROM_WRITE(planner.max_feedrate_mm_s);
456
    EEPROM_WRITE(planner.acceleration);
457
    EEPROM_WRITE(planner.retract_acceleration);
458
    EEPROM_WRITE(planner.travel_acceleration);
459
    EEPROM_WRITE(planner.min_feedrate_mm_s);
460
    EEPROM_WRITE(planner.min_travel_feedrate_mm_s);
461
 
462
    #if ENABLED(JUNCTION_DEVIATION)
463
      const float planner_max_jerk[] = {
464
        #if ENABLED(HANGPRINTER)
465
          float(DEFAULT_AJERK), float(DEFAULT_BJERK), float(DEFAULT_CJERK), float(DEFAULT_DJERK), float(DEFAULT_EJERK)
466
        #else
467
          float(DEFAULT_XJERK), float(DEFAULT_YJERK), float(DEFAULT_ZJERK), float(DEFAULT_EJERK)
468
        #endif
469
      };
470
      EEPROM_WRITE(planner_max_jerk);
471
      EEPROM_WRITE(planner.junction_deviation_mm);
472
    #else
473
      EEPROM_WRITE(planner.max_jerk);
474
      dummy = 0.02f;
475
      EEPROM_WRITE(dummy);
476
    #endif
477
 
478
    _FIELD_TEST(home_offset);
479
 
480
    #if !HAS_HOME_OFFSET
481
      const float home_offset[XYZ] = { 0 };
482
    #endif
483
    EEPROM_WRITE(home_offset);
484
 
485
    #if HOTENDS > 1
486
      // Skip hotend 0 which must be 0
487
      for (uint8_t e = 1; e < HOTENDS; e++)
488
        LOOP_XYZ(i) EEPROM_WRITE(hotend_offset[i][e]);
489
    #endif
490
 
491
    //
492
    // Global Leveling
493
    //
494
 
495
    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
496
      const float zfh = planner.z_fade_height;
497
    #else
498
      const float zfh = 10.0;
499
    #endif
500
    EEPROM_WRITE(zfh);
501
 
502
    //
503
    // Mesh Bed Leveling
504
    //
505
 
506
    #if ENABLED(MESH_BED_LEVELING)
507
      // Compile time test that sizeof(mbl.z_values) is as expected
508
      static_assert(
509
        sizeof(mbl.z_values) == GRID_MAX_POINTS * sizeof(mbl.z_values[0][0]),
510
        "MBL Z array is the wrong size."
511
      );
512
      const uint8_t mesh_num_x = GRID_MAX_POINTS_X, mesh_num_y = GRID_MAX_POINTS_Y;
513
      EEPROM_WRITE(mbl.z_offset);
514
      EEPROM_WRITE(mesh_num_x);
515
      EEPROM_WRITE(mesh_num_y);
516
      EEPROM_WRITE(mbl.z_values);
517
    #else // For disabled MBL write a default mesh
518
      dummy = 0;
519
      const uint8_t mesh_num_x = 3, mesh_num_y = 3;
520
      EEPROM_WRITE(dummy); // z_offset
521
      EEPROM_WRITE(mesh_num_x);
522
      EEPROM_WRITE(mesh_num_y);
523
      for (uint8_t q = mesh_num_x * mesh_num_y; q--;) EEPROM_WRITE(dummy);
524
    #endif // MESH_BED_LEVELING
525
 
526
    _FIELD_TEST(zprobe_zoffset);
527
 
528
    #if !HAS_BED_PROBE
529
      const float zprobe_zoffset = 0;
530
    #endif
531
    EEPROM_WRITE(zprobe_zoffset);
532
 
533
    //
534
    // Planar Bed Leveling matrix
535
    //
536
 
537
    #if ABL_PLANAR
538
      EEPROM_WRITE(planner.bed_level_matrix);
539
    #else
540
      dummy = 0;
541
      for (uint8_t q = 9; q--;) EEPROM_WRITE(dummy);
542
    #endif
543
 
544
    //
545
    // Bilinear Auto Bed Leveling
546
    //
547
 
548
    #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
549
      // Compile time test that sizeof(z_values) is as expected
550
      static_assert(
551
        sizeof(z_values) == GRID_MAX_POINTS * sizeof(z_values[0][0]),
552
        "Bilinear Z array is the wrong size."
553
      );
554
      const uint8_t grid_max_x = GRID_MAX_POINTS_X, grid_max_y = GRID_MAX_POINTS_Y;
555
      EEPROM_WRITE(grid_max_x);            // 1 byte
556
      EEPROM_WRITE(grid_max_y);            // 1 byte
557
      EEPROM_WRITE(bilinear_grid_spacing); // 2 ints
558
      EEPROM_WRITE(bilinear_start);        // 2 ints
559
      EEPROM_WRITE(z_values);              // 9-256 floats
560
    #else
561
      // For disabled Bilinear Grid write an empty 3x3 grid
562
      const uint8_t grid_max_x = 3, grid_max_y = 3;
563
      const int bilinear_start[2] = { 0 }, bilinear_grid_spacing[2] = { 0 };
564
      dummy = 0;
565
      EEPROM_WRITE(grid_max_x);
566
      EEPROM_WRITE(grid_max_y);
567
      EEPROM_WRITE(bilinear_grid_spacing);
568
      EEPROM_WRITE(bilinear_start);
569
      for (uint16_t q = grid_max_x * grid_max_y; q--;) EEPROM_WRITE(dummy);
570
    #endif // AUTO_BED_LEVELING_BILINEAR
571
 
572
    _FIELD_TEST(planner_leveling_active);
573
 
574
    #if ENABLED(AUTO_BED_LEVELING_UBL)
575
      EEPROM_WRITE(planner.leveling_active);
576
      EEPROM_WRITE(ubl.storage_slot);
577
    #else
578
      const bool ubl_active = false;
579
      const int8_t storage_slot = -1;
580
      EEPROM_WRITE(ubl_active);
581
      EEPROM_WRITE(storage_slot);
582
    #endif // AUTO_BED_LEVELING_UBL
583
 
584
    //
585
    // BLTOUCH
586
    //
587
    {
588
      _FIELD_TEST(bltouch_last_written_mode);
589
      #if ENABLED(BLTOUCH)
590
        const bool &eeprom_bltouch_last_written_mode = bltouch_last_written_mode;
591
      #else
592
        constexpr bool eeprom_bltouch_last_written_mode = false;
593
      #endif
594
      EEPROM_WRITE(eeprom_bltouch_last_written_mode);
595
    }
596
 
597
 
598
    // 11 floats for DELTA / [XYZ]_DUAL_ENDSTOPS
599
    #if ENABLED(DELTA)
600
 
601
      _FIELD_TEST(delta_height);
602
 
603
      EEPROM_WRITE(delta_height);              // 1 float
604
      EEPROM_WRITE(delta_endstop_adj);         // 3 floats
605
      EEPROM_WRITE(delta_radius);              // 1 float
606
      EEPROM_WRITE(delta_diagonal_rod);        // 1 float
607
      EEPROM_WRITE(delta_segments_per_second); // 1 float
608
      EEPROM_WRITE(delta_calibration_radius);  // 1 float
609
      EEPROM_WRITE(delta_tower_angle_trim);    // 3 floats
610
 
611
    #elif ENABLED(HANGPRINTER)
612
 
613
      dummy = 0.0f;
614
      _FIELD_TEST(anchor_A_y);
615
      EEPROM_WRITE(anchor_A_y);                // 1 float
616
      EEPROM_WRITE(anchor_A_z);                // 1 float
617
      EEPROM_WRITE(anchor_B_x);                // 1 float
618
      EEPROM_WRITE(anchor_B_y);                // 1 float
619
      EEPROM_WRITE(anchor_B_z);                // 1 float
620
      EEPROM_WRITE(anchor_C_x);                // 1 float
621
      EEPROM_WRITE(anchor_C_y);                // 1 float
622
      EEPROM_WRITE(anchor_C_z);                // 1 float
623
      EEPROM_WRITE(anchor_D_z);                // 1 float
624
      EEPROM_WRITE(delta_segments_per_second); // 1 float
625
      EEPROM_WRITE(dummy);                     // 1 float
626
 
627
    #elif ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
628
 
629
      _FIELD_TEST(x_endstop_adj);
630
 
631
      // Write dual endstops in X, Y, Z order. Unused = 0.0
632
      dummy = 0;
633
      #if ENABLED(X_DUAL_ENDSTOPS)
634
        EEPROM_WRITE(endstops.x_endstop_adj);   // 1 float
635
      #else
636
        EEPROM_WRITE(dummy);
637
      #endif
638
 
639
      #if ENABLED(Y_DUAL_ENDSTOPS)
640
        EEPROM_WRITE(endstops.y_endstop_adj);   // 1 float
641
      #else
642
        EEPROM_WRITE(dummy);
643
      #endif
644
 
645
      #if ENABLED(Z_DUAL_ENDSTOPS)
646
        EEPROM_WRITE(endstops.z_endstop_adj);   // 1 float
647
      #else
648
        EEPROM_WRITE(dummy);
649
      #endif
650
 
651
    #endif
652
 
653
    _FIELD_TEST(lcd_preheat_hotend_temp);
654
 
655
    #if DISABLED(ULTIPANEL)
656
      constexpr int16_t lcd_preheat_hotend_temp[2] = { PREHEAT_1_TEMP_HOTEND, PREHEAT_2_TEMP_HOTEND },
657
                        lcd_preheat_bed_temp[2] = { PREHEAT_1_TEMP_BED, PREHEAT_2_TEMP_BED },
658
                        lcd_preheat_fan_speed[2] = { PREHEAT_1_FAN_SPEED, PREHEAT_2_FAN_SPEED };
659
    #endif
660
 
661
    EEPROM_WRITE(lcd_preheat_hotend_temp);
662
    EEPROM_WRITE(lcd_preheat_bed_temp);
663
    EEPROM_WRITE(lcd_preheat_fan_speed);
664
 
665
    for (uint8_t e = 0; e < MAX_EXTRUDERS; e++) {
666
 
667
      #if ENABLED(PIDTEMP)
668
        if (e < HOTENDS) {
669
          EEPROM_WRITE(PID_PARAM(Kp, e));
670
          EEPROM_WRITE(PID_PARAM(Ki, e));
671
          EEPROM_WRITE(PID_PARAM(Kd, e));
672
          #if ENABLED(PID_EXTRUSION_SCALING)
673
            EEPROM_WRITE(PID_PARAM(Kc, e));
674
          #else
675
            dummy = 1.0f; // 1.0 = default kc
676
            EEPROM_WRITE(dummy);
677
          #endif
678
        }
679
        else
680
      #endif // !PIDTEMP
681
        {
682
          dummy = NAN; // When read, will not change the existing value
683
          EEPROM_WRITE(dummy); // Kp
684
          dummy = 0;
685
          for (uint8_t q = 3; q--;) EEPROM_WRITE(dummy); // Ki, Kd, Kc
686
        }
687
 
688
    } // Hotends Loop
689
 
690
    _FIELD_TEST(lpq_len);
691
 
692
    #if DISABLED(PID_EXTRUSION_SCALING)
693
      const int16_t LPQ_LEN = 20;
694
    #endif
695
    EEPROM_WRITE(LPQ_LEN);
696
 
697
    #if DISABLED(PIDTEMPBED)
698
      dummy = NAN;
699
      for (uint8_t q = 3; q--;) EEPROM_WRITE(dummy);
700
    #else
701
      EEPROM_WRITE(thermalManager.bedKp);
702
      EEPROM_WRITE(thermalManager.bedKi);
703
      EEPROM_WRITE(thermalManager.bedKd);
704
    #endif
705
 
706
    _FIELD_TEST(lcd_contrast);
707
 
708
    #if !HAS_LCD_CONTRAST
709
      const int16_t lcd_contrast = 32;
710
    #endif
711
    EEPROM_WRITE(lcd_contrast);
712
 
713
    #if DISABLED(FWRETRACT)
714
      const bool autoretract_enabled = false;
715
      const float autoretract_defaults[] = { 3, 45, 0, 0, 0, 13, 0, 8 };
716
      EEPROM_WRITE(autoretract_enabled);
717
      EEPROM_WRITE(autoretract_defaults);
718
    #else
719
      EEPROM_WRITE(fwretract.autoretract_enabled);
720
      EEPROM_WRITE(fwretract.retract_length);
721
      EEPROM_WRITE(fwretract.retract_feedrate_mm_s);
722
      EEPROM_WRITE(fwretract.retract_zlift);
723
      EEPROM_WRITE(fwretract.retract_recover_length);
724
      EEPROM_WRITE(fwretract.retract_recover_feedrate_mm_s);
725
      EEPROM_WRITE(fwretract.swap_retract_length);
726
      EEPROM_WRITE(fwretract.swap_retract_recover_length);
727
      EEPROM_WRITE(fwretract.swap_retract_recover_feedrate_mm_s);
728
    #endif
729
 
730
    //
731
    // Volumetric & Filament Size
732
    //
733
 
734
    _FIELD_TEST(parser_volumetric_enabled);
735
 
736
    #if DISABLED(NO_VOLUMETRICS)
737
 
738
      EEPROM_WRITE(parser.volumetric_enabled);
739
 
740
      // Save filament sizes
741
      for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
742
        if (q < COUNT(planner.filament_size)) dummy = planner.filament_size[q];
743
        EEPROM_WRITE(dummy);
744
      }
745
 
746
    #else
747
 
748
      const bool volumetric_enabled = false;
749
      dummy = DEFAULT_NOMINAL_FILAMENT_DIA;
750
      EEPROM_WRITE(volumetric_enabled);
751
      for (uint8_t q = MAX_EXTRUDERS; q--;) EEPROM_WRITE(dummy);
752
 
753
    #endif
754
 
755
    //
756
    // Save TMC2130 or TMC2208 Configuration, and placeholder values
757
    //
758
 
759
    _FIELD_TEST(tmc_stepper_current);
760
 
761
    uint16_t tmc_stepper_current[TMC_AXES] = {
762
      #if HAS_TRINAMIC
763
        #if AXIS_IS_TMC(X)
764
          stepperX.getCurrent(),
765
        #else
766
          0,
767
        #endif
768
        #if AXIS_IS_TMC(Y)
769
          stepperY.getCurrent(),
770
        #else
771
          0,
772
        #endif
773
        #if AXIS_IS_TMC(Z)
774
          stepperZ.getCurrent(),
775
        #else
776
          0,
777
        #endif
778
        #if AXIS_IS_TMC(X2)
779
          stepperX2.getCurrent(),
780
        #else
781
          0,
782
        #endif
783
        #if AXIS_IS_TMC(Y2)
784
          stepperY2.getCurrent(),
785
        #else
786
          0,
787
        #endif
788
        #if AXIS_IS_TMC(Z2)
789
          stepperZ2.getCurrent(),
790
        #else
791
          0,
792
        #endif
793
        #if AXIS_IS_TMC(E0)
794
          stepperE0.getCurrent(),
795
        #else
796
          0,
797
        #endif
798
        #if AXIS_IS_TMC(E1)
799
          stepperE1.getCurrent(),
800
        #else
801
          0,
802
        #endif
803
        #if AXIS_IS_TMC(E2)
804
          stepperE2.getCurrent(),
805
        #else
806
          0,
807
        #endif
808
        #if AXIS_IS_TMC(E3)
809
          stepperE3.getCurrent(),
810
        #else
811
          0,
812
        #endif
813
        #if AXIS_IS_TMC(E4)
814
          stepperE4.getCurrent()
815
        #else
816
 
817
        #endif
818
      #else
819
 
820
      #endif
821
    };
822
    EEPROM_WRITE(tmc_stepper_current);
823
 
824
    //
825
    // Save TMC2130 or TMC2208 Hybrid Threshold, and placeholder values
826
    //
827
 
828
    _FIELD_TEST(tmc_hybrid_threshold);
829
 
830
    uint32_t tmc_hybrid_threshold[TMC_AXES] = {
831
      #if ENABLED(HYBRID_THRESHOLD)
832
        #if AXIS_HAS_STEALTHCHOP(X)
833
          TMC_GET_PWMTHRS(X, X),
834
        #else
835
          X_HYBRID_THRESHOLD,
836
        #endif
837
        #if AXIS_HAS_STEALTHCHOP(Y)
838
          TMC_GET_PWMTHRS(Y, Y),
839
        #else
840
          Y_HYBRID_THRESHOLD,
841
        #endif
842
        #if AXIS_HAS_STEALTHCHOP(Z)
843
          TMC_GET_PWMTHRS(Z, Z),
844
        #else
845
          Z_HYBRID_THRESHOLD,
846
        #endif
847
        #if AXIS_HAS_STEALTHCHOP(X2)
848
          TMC_GET_PWMTHRS(X, X2),
849
        #else
850
          X2_HYBRID_THRESHOLD,
851
        #endif
852
        #if AXIS_HAS_STEALTHCHOP(Y2)
853
          TMC_GET_PWMTHRS(Y, Y2),
854
        #else
855
          Y2_HYBRID_THRESHOLD,
856
        #endif
857
        #if AXIS_HAS_STEALTHCHOP(Z2)
858
          TMC_GET_PWMTHRS(Z, Z2),
859
        #else
860
          Z2_HYBRID_THRESHOLD,
861
        #endif
862
        #if AXIS_HAS_STEALTHCHOP(E0)
863
          TMC_GET_PWMTHRS(E, E0),
864
        #else
865
          E0_HYBRID_THRESHOLD,
866
        #endif
867
        #if AXIS_HAS_STEALTHCHOP(E1)
868
          TMC_GET_PWMTHRS(E, E1),
869
        #else
870
          E1_HYBRID_THRESHOLD,
871
        #endif
872
        #if AXIS_HAS_STEALTHCHOP(E2)
873
          TMC_GET_PWMTHRS(E, E2),
874
        #else
875
          E2_HYBRID_THRESHOLD,
876
        #endif
877
        #if AXIS_HAS_STEALTHCHOP(E3)
878
          TMC_GET_PWMTHRS(E, E3),
879
        #else
880
          E3_HYBRID_THRESHOLD,
881
        #endif
882
        #if AXIS_HAS_STEALTHCHOP(E4)
883
          TMC_GET_PWMTHRS(E, E4)
884
        #else
885
          E4_HYBRID_THRESHOLD
886
        #endif
887
      #else
888
        100, 100, 3,          // X, Y, Z
889
        100, 100, 3,          // X2, Y2, Z2
890
        30, 30, 30, 30, 30    // E0, E1, E2, E3, E4
891
      #endif
892
    };
893
    EEPROM_WRITE(tmc_hybrid_threshold);
894
 
895
    //
896
    // TMC2130 Sensorless homing threshold
897
    //
898
    int16_t tmc_sgt[XYZ] = {
899
      #if ENABLED(SENSORLESS_HOMING)
900
        #if X_SENSORLESS
901
          stepperX.sgt(),
902
        #else
903
          0,
904
        #endif
905
        #if Y_SENSORLESS
906
          stepperY.sgt(),
907
        #else
908
          0,
909
        #endif
910
        #if Z_SENSORLESS
911
          stepperZ.sgt()
912
        #else
913
 
914
        #endif
915
      #else
916
 
917
      #endif
918
    };
919
    EEPROM_WRITE(tmc_sgt);
920
 
921
    //
922
    // Linear Advance
923
    //
924
 
925
    _FIELD_TEST(planner_extruder_advance_K);
926
 
927
    #if ENABLED(LIN_ADVANCE)
928
      EEPROM_WRITE(planner.extruder_advance_K);
929
    #else
930
      dummy = 0;
931
      EEPROM_WRITE(dummy);
932
    #endif
933
 
934
    _FIELD_TEST(motor_current_setting);
935
 
936
    #if HAS_MOTOR_CURRENT_PWM
937
      for (uint8_t q = XYZ; q--;) EEPROM_WRITE(stepper.motor_current_setting[q]);
938
    #else
939
      const uint32_t dummyui32[XYZ] = { 0 };
940
      EEPROM_WRITE(dummyui32);
941
    #endif
942
 
943
    //
944
    // CNC Coordinate Systems
945
    //
946
 
947
    _FIELD_TEST(coordinate_system);
948
 
949
    #if ENABLED(CNC_COORDINATE_SYSTEMS)
950
      EEPROM_WRITE(coordinate_system); // 27 floats
951
    #else
952
      dummy = 0;
953
      for (uint8_t q = MAX_COORDINATE_SYSTEMS * XYZ; q--;) EEPROM_WRITE(dummy);
954
    #endif
955
 
956
    //
957
    // Skew correction factors
958
    //
959
 
960
    _FIELD_TEST(planner_xy_skew_factor);
961
 
962
    #if ENABLED(SKEW_CORRECTION)
963
      EEPROM_WRITE(planner.xy_skew_factor);
964
      EEPROM_WRITE(planner.xz_skew_factor);
965
      EEPROM_WRITE(planner.yz_skew_factor);
966
    #else
967
      dummy = 0;
968
      for (uint8_t q = 3; q--;) EEPROM_WRITE(dummy);
969
    #endif
970
 
971
    //
972
    // Advanced Pause filament load & unload lengths
973
    //
974
 
975
    _FIELD_TEST(filament_change_unload_length);
976
 
977
    #if ENABLED(ADVANCED_PAUSE_FEATURE)
978
      for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
979
        if (q < COUNT(filament_change_unload_length)) dummy = filament_change_unload_length[q];
980
        EEPROM_WRITE(dummy);
981
      }
982
      for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
983
        if (q < COUNT(filament_change_load_length)) dummy = filament_change_load_length[q];
984
        EEPROM_WRITE(dummy);
985
      }
986
    #else
987
      dummy = 0;
988
      for (uint8_t q = MAX_EXTRUDERS * 2; q--;) EEPROM_WRITE(dummy);
989
    #endif
990
 
991
    //
992
    // Validate CRC and Data Size
993
    //
994
    if (!eeprom_error) {
995
      const uint16_t eeprom_size = eeprom_index - (EEPROM_OFFSET),
996
                     final_crc = working_crc;
997
 
998
      // Write the EEPROM header
999
      eeprom_index = EEPROM_OFFSET;
1000
 
1001
      EEPROM_WRITE(version);
1002
      EEPROM_WRITE(final_crc);
1003
 
1004
      // Report storage size
1005
      #if ENABLED(EEPROM_CHITCHAT)
1006
        SERIAL_ECHO_START();
1007
        SERIAL_ECHOPAIR("Settings Stored (", eeprom_size);
1008
        SERIAL_ECHOPAIR(" bytes; crc ", (uint32_t)final_crc);
1009
        SERIAL_ECHOLNPGM(")");
1010
      #endif
1011
 
1012
      eeprom_error |= size_error(eeprom_size);
1013
    }
1014
 
1015
    //
1016
    // UBL Mesh
1017
    //
1018
    #if ENABLED(UBL_SAVE_ACTIVE_ON_M500)
1019
      if (ubl.storage_slot >= 0)
1020
        store_mesh(ubl.storage_slot);
1021
    #endif
1022
 
1023
    return !eeprom_error;
1024
  }
1025
 
1026
  /**
1027
   * M501 - Retrieve Configuration
1028
   */
1029
  bool MarlinSettings::_load() {
1030
    uint16_t working_crc = 0;
1031
 
1032
    EEPROM_START();
1033
 
1034
    char stored_ver[4];
1035
    EEPROM_READ_ALWAYS(stored_ver);
1036
 
1037
    uint16_t stored_crc;
1038
    EEPROM_READ_ALWAYS(stored_crc);
1039
 
1040
    // Version has to match or defaults are used
1041
    if (strncmp(version, stored_ver, 3) != 0) {
1042
      if (stored_ver[3] != '\0') {
1043
        stored_ver[0] = '?';
1044
        stored_ver[1] = '\0';
1045
      }
1046
      #if ENABLED(EEPROM_CHITCHAT)
1047
        SERIAL_ECHO_START();
1048
        SERIAL_ECHOPGM("EEPROM version mismatch ");
1049
        SERIAL_ECHOPAIR("(EEPROM=", stored_ver);
1050
        SERIAL_ECHOLNPGM(" Marlin=" EEPROM_VERSION ")");
1051
      #endif
1052
      eeprom_error = true;
1053
    }
1054
    else {
1055
      float dummy = 0;
1056
      #if DISABLED(AUTO_BED_LEVELING_UBL) || DISABLED(FWRETRACT) || ENABLED(NO_VOLUMETRICS)
1057
        bool dummyb;
1058
      #endif
1059
 
1060
      working_crc = 0;  // Init to 0. Accumulated by EEPROM_READ
1061
 
1062
      _FIELD_TEST(esteppers);
1063
 
1064
      // Number of esteppers may change
1065
      uint8_t esteppers;
1066
      EEPROM_READ_ALWAYS(esteppers);
1067
 
1068
      //
1069
      // Planner Motion
1070
      //
1071
 
1072
      // Get only the number of E stepper parameters previously stored
1073
      // Any steppers added later are set to their defaults
1074
      const uint32_t def1[] = DEFAULT_MAX_ACCELERATION;
1075
      const float def2[] = DEFAULT_AXIS_STEPS_PER_UNIT, def3[] = DEFAULT_MAX_FEEDRATE;
1076
 
1077
      uint32_t tmp1[MOV_AXIS + esteppers];
1078
      EEPROM_READ(tmp1);                         // max_acceleration_mm_per_s2
1079
      EEPROM_READ(planner.min_segment_time_us);
1080
 
1081
      float tmp2[MOV_AXIS + esteppers], tmp3[MOV_AXIS + esteppers];
1082
      EEPROM_READ(tmp2);                         // axis_steps_per_mm
1083
      EEPROM_READ(tmp3);                         // max_feedrate_mm_s
1084
      if (!validating) LOOP_NUM_AXIS_N(i) {
1085
        planner.max_acceleration_mm_per_s2[i] = i < MOV_AXIS + esteppers ? tmp1[i] : def1[i < COUNT(def1) ? i : COUNT(def1) - 1];
1086
        planner.axis_steps_per_mm[i]          = i < MOV_AXIS + esteppers ? tmp2[i] : def2[i < COUNT(def2) ? i : COUNT(def2) - 1];
1087
        planner.max_feedrate_mm_s[i]          = i < MOV_AXIS + esteppers ? tmp3[i] : def3[i < COUNT(def3) ? i : COUNT(def3) - 1];
1088
      }
1089
 
1090
      EEPROM_READ(planner.acceleration);
1091
      EEPROM_READ(planner.retract_acceleration);
1092
      EEPROM_READ(planner.travel_acceleration);
1093
      EEPROM_READ(planner.min_feedrate_mm_s);
1094
      EEPROM_READ(planner.min_travel_feedrate_mm_s);
1095
 
1096
      #if ENABLED(JUNCTION_DEVIATION)
1097
        for (uint8_t q = 4; q--;) EEPROM_READ(dummy);
1098
        EEPROM_READ(planner.junction_deviation_mm);
1099
      #else
1100
        EEPROM_READ(planner.max_jerk);
1101
        EEPROM_READ(dummy);
1102
      #endif
1103
 
1104
      //
1105
      // Home Offset (M206)
1106
      //
1107
 
1108
      _FIELD_TEST(home_offset);
1109
 
1110
      #if !HAS_HOME_OFFSET
1111
        float home_offset[XYZ];
1112
      #endif
1113
      EEPROM_READ(home_offset);
1114
 
1115
      //
1116
      // Hotend Offsets, if any
1117
      //
1118
 
1119
      #if HOTENDS > 1
1120
        // Skip hotend 0 which must be 0
1121
        for (uint8_t e = 1; e < HOTENDS; e++)
1122
          LOOP_XYZ(i) EEPROM_READ(hotend_offset[i][e]);
1123
      #endif
1124
 
1125
      //
1126
      // Global Leveling
1127
      //
1128
 
1129
      #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
1130
        EEPROM_READ(new_z_fade_height);
1131
      #else
1132
        EEPROM_READ(dummy);
1133
      #endif
1134
 
1135
      //
1136
      // Mesh (Manual) Bed Leveling
1137
      //
1138
 
1139
      uint8_t mesh_num_x, mesh_num_y;
1140
      EEPROM_READ(dummy);
1141
      EEPROM_READ_ALWAYS(mesh_num_x);
1142
      EEPROM_READ_ALWAYS(mesh_num_y);
1143
 
1144
      #if ENABLED(MESH_BED_LEVELING)
1145
        if (!validating) mbl.z_offset = dummy;
1146
        if (mesh_num_x == GRID_MAX_POINTS_X && mesh_num_y == GRID_MAX_POINTS_Y) {
1147
          // EEPROM data fits the current mesh
1148
          EEPROM_READ(mbl.z_values);
1149
        }
1150
        else {
1151
          // EEPROM data is stale
1152
          if (!validating) mbl.reset();
1153
          for (uint16_t q = mesh_num_x * mesh_num_y; q--;) EEPROM_READ(dummy);
1154
        }
1155
      #else
1156
        // MBL is disabled - skip the stored data
1157
        for (uint16_t q = mesh_num_x * mesh_num_y; q--;) EEPROM_READ(dummy);
1158
      #endif // MESH_BED_LEVELING
1159
 
1160
      _FIELD_TEST(zprobe_zoffset);
1161
 
1162
      #if !HAS_BED_PROBE
1163
        float zprobe_zoffset;
1164
      #endif
1165
      EEPROM_READ(zprobe_zoffset);
1166
 
1167
      //
1168
      // Planar Bed Leveling matrix
1169
      //
1170
 
1171
      #if ABL_PLANAR
1172
        EEPROM_READ(planner.bed_level_matrix);
1173
      #else
1174
        for (uint8_t q = 9; q--;) EEPROM_READ(dummy);
1175
      #endif
1176
 
1177
      //
1178
      // Bilinear Auto Bed Leveling
1179
      //
1180
 
1181
      uint8_t grid_max_x, grid_max_y;
1182
      EEPROM_READ_ALWAYS(grid_max_x);                       // 1 byte
1183
      EEPROM_READ_ALWAYS(grid_max_y);                       // 1 byte
1184
      #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
1185
        if (grid_max_x == GRID_MAX_POINTS_X && grid_max_y == GRID_MAX_POINTS_Y) {
1186
          if (!validating) set_bed_leveling_enabled(false);
1187
          EEPROM_READ(bilinear_grid_spacing);        // 2 ints
1188
          EEPROM_READ(bilinear_start);               // 2 ints
1189
          EEPROM_READ(z_values);                     // 9 to 256 floats
1190
        }
1191
        else // EEPROM data is stale
1192
      #endif // AUTO_BED_LEVELING_BILINEAR
1193
        {
1194
          // Skip past disabled (or stale) Bilinear Grid data
1195
          int bgs[2], bs[2];
1196
          EEPROM_READ(bgs);
1197
          EEPROM_READ(bs);
1198
          for (uint16_t q = grid_max_x * grid_max_y; q--;) EEPROM_READ(dummy);
1199
        }
1200
 
1201
      //
1202
      // Unified Bed Leveling active state
1203
      //
1204
 
1205
      _FIELD_TEST(planner_leveling_active);
1206
 
1207
      #if ENABLED(AUTO_BED_LEVELING_UBL)
1208
        EEPROM_READ(planner.leveling_active);
1209
        EEPROM_READ(ubl.storage_slot);
1210
      #else
1211
        uint8_t dummyui8;
1212
        EEPROM_READ(dummyb);
1213
        EEPROM_READ(dummyui8);
1214
      #endif // AUTO_BED_LEVELING_UBL
1215
 
1216
      //
1217
      // BLTOUCH
1218
      //
1219
      {
1220
        _FIELD_TEST(bltouch_last_written_mode);
1221
        #if ENABLED(BLTOUCH)
1222
          bool &eeprom_bltouch_last_written_mode = bltouch_last_written_mode;
1223
        #else
1224
          bool eeprom_bltouch_last_written_mode;
1225
        #endif
1226
        EEPROM_READ(eeprom_bltouch_last_written_mode);
1227
      }
1228
 
1229
      //
1230
      // DELTA Geometry or Dual Endstops offsets
1231
      //
1232
 
1233
      #if ENABLED(DELTA)
1234
 
1235
        _FIELD_TEST(delta_height);
1236
 
1237
        EEPROM_READ(delta_height);              // 1 float
1238
        EEPROM_READ(delta_endstop_adj);         // 3 floats
1239
        EEPROM_READ(delta_radius);              // 1 float
1240
        EEPROM_READ(delta_diagonal_rod);        // 1 float
1241
        EEPROM_READ(delta_segments_per_second); // 1 float
1242
        EEPROM_READ(delta_calibration_radius);  // 1 float
1243
        EEPROM_READ(delta_tower_angle_trim);    // 3 floats
1244
 
1245
      #elif ENABLED(HANGPRINTER)
1246
        EEPROM_READ(anchor_A_y);                // 1 float
1247
        EEPROM_READ(anchor_A_z);                // 1 float
1248
        EEPROM_READ(anchor_B_x);                // 1 float
1249
        EEPROM_READ(anchor_B_y);                // 1 float
1250
        EEPROM_READ(anchor_B_z);                // 1 float
1251
        EEPROM_READ(anchor_C_x);                // 1 float
1252
        EEPROM_READ(anchor_C_y);                // 1 float
1253
        EEPROM_READ(anchor_C_z);                // 1 float
1254
        EEPROM_READ(anchor_D_z);                // 1 float
1255
        EEPROM_READ(delta_segments_per_second); // 1 float
1256
        EEPROM_READ(dummy);                     // 1 float
1257
 
1258
      #elif ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
1259
 
1260
        _FIELD_TEST(x_endstop_adj);
1261
 
1262
        #if ENABLED(X_DUAL_ENDSTOPS)
1263
          EEPROM_READ(endstops.x_endstop_adj);  // 1 float
1264
        #else
1265
          EEPROM_READ(dummy);
1266
        #endif
1267
        #if ENABLED(Y_DUAL_ENDSTOPS)
1268
          EEPROM_READ(endstops.y_endstop_adj);  // 1 float
1269
        #else
1270
          EEPROM_READ(dummy);
1271
        #endif
1272
        #if ENABLED(Z_DUAL_ENDSTOPS)
1273
          EEPROM_READ(endstops.z_endstop_adj); // 1 float
1274
        #else
1275
          EEPROM_READ(dummy);
1276
        #endif
1277
 
1278
      #endif
1279
 
1280
      //
1281
      // LCD Preheat settings
1282
      //
1283
 
1284
      _FIELD_TEST(lcd_preheat_hotend_temp);
1285
 
1286
      #if DISABLED(ULTIPANEL)
1287
        int16_t lcd_preheat_hotend_temp[2], lcd_preheat_bed_temp[2], lcd_preheat_fan_speed[2];
1288
      #endif
1289
      EEPROM_READ(lcd_preheat_hotend_temp); // 2 floats
1290
      EEPROM_READ(lcd_preheat_bed_temp);    // 2 floats
1291
      EEPROM_READ(lcd_preheat_fan_speed);   // 2 floats
1292
 
1293
      //EEPROM_ASSERT(
1294
      //  WITHIN(lcd_preheat_fan_speed, 0, 255),
1295
      //  "lcd_preheat_fan_speed out of range"
1296
      //);
1297
 
1298
      //
1299
      // Hotend PID
1300
      //
1301
 
1302
      #if ENABLED(PIDTEMP)
1303
        for (uint8_t e = 0; e < MAX_EXTRUDERS; e++) {
1304
          EEPROM_READ(dummy); // Kp
1305
          if (e < HOTENDS && !isnan(dummy)) {
1306
            // do not need to scale PID values as the values in EEPROM are already scaled
1307
            if (!validating) PID_PARAM(Kp, e) = dummy;
1308
            EEPROM_READ(PID_PARAM(Ki, e));
1309
            EEPROM_READ(PID_PARAM(Kd, e));
1310
            #if ENABLED(PID_EXTRUSION_SCALING)
1311
              EEPROM_READ(PID_PARAM(Kc, e));
1312
            #else
1313
              EEPROM_READ(dummy);
1314
            #endif
1315
          }
1316
          else {
1317
            for (uint8_t q=3; q--;) EEPROM_READ(dummy); // Ki, Kd, Kc
1318
          }
1319
        }
1320
      #else // !PIDTEMP
1321
        // 4 x 4 = 16 slots for PID parameters
1322
        for (uint8_t q = MAX_EXTRUDERS * 4; q--;) EEPROM_READ(dummy);  // Kp, Ki, Kd, Kc
1323
      #endif // !PIDTEMP
1324
 
1325
      //
1326
      // PID Extrusion Scaling
1327
      //
1328
 
1329
      _FIELD_TEST(lpq_len);
1330
 
1331
      #if DISABLED(PID_EXTRUSION_SCALING)
1332
        int16_t LPQ_LEN;
1333
      #endif
1334
      EEPROM_READ(LPQ_LEN);
1335
 
1336
      //
1337
      // Heated Bed PID
1338
      //
1339
 
1340
      #if ENABLED(PIDTEMPBED)
1341
        EEPROM_READ(dummy); // bedKp
1342
        if (!isnan(dummy)) {
1343
          if (!validating) thermalManager.bedKp = dummy;
1344
          EEPROM_READ(thermalManager.bedKi);
1345
          EEPROM_READ(thermalManager.bedKd);
1346
        }
1347
      #else
1348
        for (uint8_t q=3; q--;) EEPROM_READ(dummy); // bedKp, bedKi, bedKd
1349
      #endif
1350
 
1351
      //
1352
      // LCD Contrast
1353
      //
1354
 
1355
      _FIELD_TEST(lcd_contrast);
1356
 
1357
      #if !HAS_LCD_CONTRAST
1358
        int16_t lcd_contrast;
1359
      #endif
1360
      EEPROM_READ(lcd_contrast);
1361
 
1362
      //
1363
      // Firmware Retraction
1364
      //
1365
 
1366
      #if ENABLED(FWRETRACT)
1367
        EEPROM_READ(fwretract.autoretract_enabled);
1368
        EEPROM_READ(fwretract.retract_length);
1369
        EEPROM_READ(fwretract.retract_feedrate_mm_s);
1370
        EEPROM_READ(fwretract.retract_zlift);
1371
        EEPROM_READ(fwretract.retract_recover_length);
1372
        EEPROM_READ(fwretract.retract_recover_feedrate_mm_s);
1373
        EEPROM_READ(fwretract.swap_retract_length);
1374
        EEPROM_READ(fwretract.swap_retract_recover_length);
1375
        EEPROM_READ(fwretract.swap_retract_recover_feedrate_mm_s);
1376
      #else
1377
        EEPROM_READ(dummyb);
1378
        for (uint8_t q=8; q--;) EEPROM_READ(dummy);
1379
      #endif
1380
 
1381
      //
1382
      // Volumetric & Filament Size
1383
      //
1384
 
1385
      _FIELD_TEST(parser_volumetric_enabled);
1386
 
1387
      #if DISABLED(NO_VOLUMETRICS)
1388
 
1389
        EEPROM_READ(parser.volumetric_enabled);
1390
 
1391
        for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
1392
          EEPROM_READ(dummy);
1393
          if (!validating && q < COUNT(planner.filament_size))
1394
            planner.filament_size[q] = dummy;
1395
        }
1396
 
1397
      #else
1398
 
1399
        EEPROM_READ(dummyb);
1400
        for (uint8_t q=MAX_EXTRUDERS; q--;) EEPROM_READ(dummy);
1401
 
1402
      #endif
1403
 
1404
      if (!validating) reset_stepper_drivers();
1405
 
1406
      //
1407
      // TMC2130 Stepper Settings
1408
      //
1409
 
1410
      _FIELD_TEST(tmc_stepper_current);
1411
 
1412
      #if HAS_TRINAMIC
1413
 
1414
        #define SET_CURR(Q) stepper##Q.setCurrent(currents[TMC_##Q] ? currents[TMC_##Q] : Q##_CURRENT, R_SENSE, HOLD_MULTIPLIER)
1415
        uint16_t currents[TMC_AXES];
1416
        EEPROM_READ(currents);
1417
        if (!validating) {
1418
          #if AXIS_IS_TMC(X)
1419
            SET_CURR(X);
1420
          #endif
1421
          #if AXIS_IS_TMC(Y)
1422
            SET_CURR(Y);
1423
          #endif
1424
          #if AXIS_IS_TMC(Z)
1425
            SET_CURR(Z);
1426
          #endif
1427
          #if AXIS_IS_TMC(X2)
1428
            SET_CURR(X2);
1429
          #endif
1430
          #if AXIS_IS_TMC(Y2)
1431
            SET_CURR(Y2);
1432
          #endif
1433
          #if AXIS_IS_TMC(Z2)
1434
            SET_CURR(Z2);
1435
          #endif
1436
          #if AXIS_IS_TMC(E0)
1437
            SET_CURR(E0);
1438
          #endif
1439
          #if AXIS_IS_TMC(E1)
1440
            SET_CURR(E1);
1441
          #endif
1442
          #if AXIS_IS_TMC(E2)
1443
            SET_CURR(E2);
1444
          #endif
1445
          #if AXIS_IS_TMC(E3)
1446
            SET_CURR(E3);
1447
          #endif
1448
          #if AXIS_IS_TMC(E4)
1449
            SET_CURR(E4);
1450
          #endif
1451
        }
1452
      #else
1453
        uint16_t val;
1454
        for (uint8_t q=TMC_AXES; q--;) EEPROM_READ(val);
1455
      #endif
1456
 
1457
      #if ENABLED(HYBRID_THRESHOLD)
1458
        #define TMC_SET_PWMTHRS(A,Q) tmc_set_pwmthrs(stepper##Q, tmc_hybrid_threshold[TMC_##Q], planner.axis_steps_per_mm[_AXIS(A)])
1459
        uint32_t tmc_hybrid_threshold[TMC_AXES];
1460
        EEPROM_READ(tmc_hybrid_threshold);
1461
        if (!validating) {
1462
          #if AXIS_HAS_STEALTHCHOP(X)
1463
            TMC_SET_PWMTHRS(X, X);
1464
          #endif
1465
          #if AXIS_HAS_STEALTHCHOP(Y)
1466
            TMC_SET_PWMTHRS(Y, Y);
1467
          #endif
1468
          #if AXIS_HAS_STEALTHCHOP(Z)
1469
            TMC_SET_PWMTHRS(Z, Z);
1470
          #endif
1471
          #if AXIS_HAS_STEALTHCHOP(X2)
1472
            TMC_SET_PWMTHRS(X, X2);
1473
          #endif
1474
          #if AXIS_HAS_STEALTHCHOP(Y2)
1475
            TMC_SET_PWMTHRS(Y, Y2);
1476
          #endif
1477
          #if AXIS_HAS_STEALTHCHOP(Z2)
1478
            TMC_SET_PWMTHRS(Z, Z2);
1479
          #endif
1480
          #if AXIS_HAS_STEALTHCHOP(E0)
1481
            TMC_SET_PWMTHRS(E, E0);
1482
          #endif
1483
          #if AXIS_HAS_STEALTHCHOP(E1)
1484
            TMC_SET_PWMTHRS(E, E1);
1485
          #endif
1486
          #if AXIS_HAS_STEALTHCHOP(E2)
1487
            TMC_SET_PWMTHRS(E, E2);
1488
          #endif
1489
          #if AXIS_HAS_STEALTHCHOP(E3)
1490
            TMC_SET_PWMTHRS(E, E3);
1491
          #endif
1492
          #if AXIS_HAS_STEALTHCHOP(E4)
1493
            TMC_SET_PWMTHRS(E, E4);
1494
          #endif
1495
        }
1496
      #else
1497
        uint32_t thrs_val;
1498
        for (uint8_t q=TMC_AXES; q--;) EEPROM_READ(thrs_val);
1499
      #endif
1500
 
1501
      /*
1502
       * TMC2130 Sensorless homing threshold.
1503
       * X and X2 use the same value
1504
       * Y and Y2 use the same value
1505
       * Z and Z2 use the same value
1506
       */
1507
      int16_t tmc_sgt[XYZ];
1508
      EEPROM_READ(tmc_sgt);
1509
      #if ENABLED(SENSORLESS_HOMING)
1510
        if (!validating) {
1511
          #ifdef X_HOMING_SENSITIVITY
1512
            #if AXIS_HAS_STALLGUARD(X)
1513
              stepperX.sgt(tmc_sgt[0]);
1514
            #endif
1515
            #if AXIS_HAS_STALLGUARD(X2)
1516
              stepperX2.sgt(tmc_sgt[0]);
1517
            #endif
1518
          #endif
1519
          #ifdef Y_HOMING_SENSITIVITY
1520
            #if AXIS_HAS_STALLGUARD(Y)
1521
              stepperY.sgt(tmc_sgt[1]);
1522
            #endif
1523
            #if AXIS_HAS_STALLGUARD(Y2)
1524
              stepperY2.sgt(tmc_sgt[1]);
1525
            #endif
1526
          #endif
1527
          #ifdef Z_HOMING_SENSITIVITY
1528
            #if AXIS_HAS_STALLGUARD(Z)
1529
              stepperZ.sgt(tmc_sgt[2]);
1530
            #endif
1531
            #if AXIS_HAS_STALLGUARD(Z2)
1532
              stepperZ2.sgt(tmc_sgt[2]);
1533
            #endif
1534
          #endif
1535
        }
1536
      #endif
1537
 
1538
      //
1539
      // Linear Advance
1540
      //
1541
 
1542
      _FIELD_TEST(planner_extruder_advance_K);
1543
 
1544
      #if ENABLED(LIN_ADVANCE)
1545
        EEPROM_READ(planner.extruder_advance_K);
1546
      #else
1547
        EEPROM_READ(dummy);
1548
      #endif
1549
 
1550
      //
1551
      // Motor Current PWM
1552
      //
1553
 
1554
      _FIELD_TEST(motor_current_setting);
1555
 
1556
      #if HAS_MOTOR_CURRENT_PWM
1557
        for (uint8_t q = XYZ; q--;) EEPROM_READ(stepper.motor_current_setting[q]);
1558
      #else
1559
        uint32_t dummyui32[XYZ];
1560
        EEPROM_READ(dummyui32);
1561
      #endif
1562
 
1563
      //
1564
      // CNC Coordinate System
1565
      //
1566
 
1567
      _FIELD_TEST(coordinate_system);
1568
 
1569
      #if ENABLED(CNC_COORDINATE_SYSTEMS)
1570
        if (!validating) (void)select_coordinate_system(-1); // Go back to machine space
1571
        EEPROM_READ(coordinate_system);                  // 27 floats
1572
      #else
1573
        for (uint8_t q = MAX_COORDINATE_SYSTEMS * XYZ; q--;) EEPROM_READ(dummy);
1574
      #endif
1575
 
1576
      //
1577
      // Skew correction factors
1578
      //
1579
 
1580
      _FIELD_TEST(planner_xy_skew_factor);
1581
 
1582
      #if ENABLED(SKEW_CORRECTION_GCODE)
1583
        EEPROM_READ(planner.xy_skew_factor);
1584
        #if ENABLED(SKEW_CORRECTION_FOR_Z)
1585
          EEPROM_READ(planner.xz_skew_factor);
1586
          EEPROM_READ(planner.yz_skew_factor);
1587
        #else
1588
          EEPROM_READ(dummy);
1589
          EEPROM_READ(dummy);
1590
        #endif
1591
      #else
1592
        for (uint8_t q = 3; q--;) EEPROM_READ(dummy);
1593
      #endif
1594
 
1595
      //
1596
      // Advanced Pause filament load & unload lengths
1597
      //
1598
 
1599
      _FIELD_TEST(filament_change_unload_length);
1600
 
1601
      #if ENABLED(ADVANCED_PAUSE_FEATURE)
1602
        for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
1603
          EEPROM_READ(dummy);
1604
          if (!validating && q < COUNT(filament_change_unload_length)) filament_change_unload_length[q] = dummy;
1605
        }
1606
        for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
1607
          EEPROM_READ(dummy);
1608
          if (!validating && q < COUNT(filament_change_load_length)) filament_change_load_length[q] = dummy;
1609
        }
1610
      #else
1611
        for (uint8_t q = MAX_EXTRUDERS * 2; q--;) EEPROM_READ(dummy);
1612
      #endif
1613
 
1614
      eeprom_error = size_error(eeprom_index - (EEPROM_OFFSET));
1615
      if (eeprom_error) {
1616
        SERIAL_ECHO_START();
1617
        SERIAL_ECHOPAIR("Index: ", int(eeprom_index - (EEPROM_OFFSET)));
1618
        SERIAL_ECHOLNPAIR(" Size: ", datasize());
1619
      }
1620
      else if (working_crc != stored_crc) {
1621
        eeprom_error = true;
1622
        #if ENABLED(EEPROM_CHITCHAT)
1623
          SERIAL_ERROR_START();
1624
          SERIAL_ERRORPGM("EEPROM CRC mismatch - (stored) ");
1625
          SERIAL_ERROR(stored_crc);
1626
          SERIAL_ERRORPGM(" != ");
1627
          SERIAL_ERROR(working_crc);
1628
          SERIAL_ERRORLNPGM(" (calculated)!");
1629
        #endif
1630
      }
1631
      else if (!validating) {
1632
        #if ENABLED(EEPROM_CHITCHAT)
1633
          SERIAL_ECHO_START();
1634
          SERIAL_ECHO(version);
1635
          SERIAL_ECHOPAIR(" stored settings retrieved (", eeprom_index - (EEPROM_OFFSET));
1636
          SERIAL_ECHOPAIR(" bytes; crc ", (uint32_t)working_crc);
1637
          SERIAL_ECHOLNPGM(")");
1638
        #endif
1639
      }
1640
 
1641
      if (!validating && !eeprom_error) postprocess();
1642
 
1643
      #if ENABLED(AUTO_BED_LEVELING_UBL)
1644
        if (!validating) {
1645
          ubl.report_state();
1646
 
1647
          if (!ubl.sanity_check()) {
1648
            SERIAL_EOL();
1649
            #if ENABLED(EEPROM_CHITCHAT)
1650
              ubl.echo_name();
1651
              SERIAL_ECHOLNPGM(" initialized.\n");
1652
            #endif
1653
          }
1654
          else {
1655
            eeprom_error = true;
1656
            #if ENABLED(EEPROM_CHITCHAT)
1657
              SERIAL_PROTOCOLPGM("?Can't enable ");
1658
              ubl.echo_name();
1659
              SERIAL_PROTOCOLLNPGM(".");
1660
            #endif
1661
            ubl.reset();
1662
          }
1663
 
1664
          if (ubl.storage_slot >= 0) {
1665
            load_mesh(ubl.storage_slot);
1666
            #if ENABLED(EEPROM_CHITCHAT)
1667
              SERIAL_ECHOPAIR("Mesh ", ubl.storage_slot);
1668
              SERIAL_ECHOLNPGM(" loaded from storage.");
1669
            #endif
1670
          }
1671
          else {
1672
            ubl.reset();
1673
            #if ENABLED(EEPROM_CHITCHAT)
1674
              SERIAL_ECHOLNPGM("UBL System reset()");
1675
            #endif
1676
          }
1677
        }
1678
      #endif
1679
    }
1680
 
1681
    #if ENABLED(EEPROM_CHITCHAT) && DISABLED(DISABLE_M503)
1682
      if (!validating) report();
1683
    #endif
1684
 
1685
    return !eeprom_error;
1686
  }
1687
 
1688
  bool MarlinSettings::validate() {
1689
    validating = true;
1690
    const bool success = _load();
1691
    validating = false;
1692
    return success;
1693
  }
1694
 
1695
  bool MarlinSettings::load() {
1696
    if (validate()) return _load();
1697
    reset();
1698
    return true;
1699
  }
1700
 
1701
  #if ENABLED(AUTO_BED_LEVELING_UBL)
1702
 
1703
    #if ENABLED(EEPROM_CHITCHAT)
1704
      void ubl_invalid_slot(const int s) {
1705
        SERIAL_PROTOCOLLNPGM("?Invalid slot.");
1706
        SERIAL_PROTOCOL(s);
1707
        SERIAL_PROTOCOLLNPGM(" mesh slots available.");
1708
      }
1709
    #endif
1710
 
1711
    uint16_t MarlinSettings::meshes_start_index() {
1712
      return (datasize() + EEPROM_OFFSET + 32) & 0xFFF8;  // Pad the end of configuration data so it can float up
1713
                                                          // or down a little bit without disrupting the mesh data
1714
    }
1715
 
1716
    uint16_t MarlinSettings::calc_num_meshes() {
1717
      return (meshes_end - meshes_start_index()) / sizeof(ubl.z_values);
1718
    }
1719
 
1720
    int MarlinSettings::mesh_slot_offset(const int8_t slot) {
1721
      return meshes_end - (slot + 1) * sizeof(ubl.z_values);
1722
    }
1723
 
1724
    void MarlinSettings::store_mesh(const int8_t slot) {
1725
 
1726
      #if ENABLED(AUTO_BED_LEVELING_UBL)
1727
        const int16_t a = calc_num_meshes();
1728
        if (!WITHIN(slot, 0, a - 1)) {
1729
          #if ENABLED(EEPROM_CHITCHAT)
1730
            ubl_invalid_slot(a);
1731
            SERIAL_PROTOCOLPAIR("E2END=", E2END);
1732
            SERIAL_PROTOCOLPAIR(" meshes_end=", meshes_end);
1733
            SERIAL_PROTOCOLLNPAIR(" slot=", slot);
1734
            SERIAL_EOL();
1735
          #endif
1736
          return;
1737
        }
1738
 
1739
        int pos = mesh_slot_offset(slot);
1740
        uint16_t crc = 0;
1741
        write_data(pos, (uint8_t *)&ubl.z_values, sizeof(ubl.z_values), &crc);
1742
 
1743
        // Write crc to MAT along with other data, or just tack on to the beginning or end
1744
 
1745
        #if ENABLED(EEPROM_CHITCHAT)
1746
          SERIAL_PROTOCOLLNPAIR("Mesh saved in slot ", slot);
1747
        #endif
1748
 
1749
      #else
1750
 
1751
        // Other mesh types
1752
 
1753
      #endif
1754
    }
1755
 
1756
    void MarlinSettings::load_mesh(const int8_t slot, void * const into/*=NULL*/) {
1757
 
1758
      #if ENABLED(AUTO_BED_LEVELING_UBL)
1759
 
1760
        const int16_t a = settings.calc_num_meshes();
1761
 
1762
        if (!WITHIN(slot, 0, a - 1)) {
1763
          #if ENABLED(EEPROM_CHITCHAT)
1764
            ubl_invalid_slot(a);
1765
          #endif
1766
          return;
1767
        }
1768
 
1769
        int pos = mesh_slot_offset(slot);
1770
        uint16_t crc = 0;
1771
        uint8_t * const dest = into ? (uint8_t*)into : (uint8_t*)&ubl.z_values;
1772
        read_data(pos, dest, sizeof(ubl.z_values), &crc);
1773
 
1774
        // Compare crc with crc from MAT, or read from end
1775
 
1776
        #if ENABLED(EEPROM_CHITCHAT)
1777
          SERIAL_PROTOCOLLNPAIR("Mesh loaded from slot ", slot);
1778
        #endif
1779
 
1780
      #else
1781
 
1782
        // Other mesh types
1783
 
1784
      #endif
1785
    }
1786
 
1787
    //void MarlinSettings::delete_mesh() { return; }
1788
    //void MarlinSettings::defrag_meshes() { return; }
1789
 
1790
  #endif // AUTO_BED_LEVELING_UBL
1791
 
1792
#else // !EEPROM_SETTINGS
1793
 
1794
  bool MarlinSettings::save() {
1795
    SERIAL_ERROR_START();
1796
    SERIAL_ERRORLNPGM("EEPROM disabled");
1797
    return false;
1798
  }
1799
 
1800
#endif // !EEPROM_SETTINGS
1801
 
1802
/**
1803
 * M502 - Reset Configuration
1804
 */
1805
void MarlinSettings::reset() {
1806
  static const float tmp1[] PROGMEM = DEFAULT_AXIS_STEPS_PER_UNIT, tmp2[] PROGMEM = DEFAULT_MAX_FEEDRATE;
1807
 
1808
  static const uint32_t tmp3[] PROGMEM = DEFAULT_MAX_ACCELERATION;
1809
  LOOP_NUM_AXIS_N(i) {
1810
    planner.axis_steps_per_mm[i]          = pgm_read_float(&tmp1[i < COUNT(tmp1) ? i : COUNT(tmp1) - 1]);
1811
    planner.max_feedrate_mm_s[i]          = pgm_read_float(&tmp2[i < COUNT(tmp2) ? i : COUNT(tmp2) - 1]);
1812
    planner.max_acceleration_mm_per_s2[i] = pgm_read_dword_near(&tmp3[i < COUNT(tmp3) ? i : COUNT(tmp3) - 1]);
1813
  }
1814
 
1815
  planner.min_segment_time_us = DEFAULT_MINSEGMENTTIME;
1816
  planner.acceleration = DEFAULT_ACCELERATION;
1817
  planner.retract_acceleration = DEFAULT_RETRACT_ACCELERATION;
1818
  planner.travel_acceleration = DEFAULT_TRAVEL_ACCELERATION;
1819
  planner.min_feedrate_mm_s = DEFAULT_MINIMUMFEEDRATE;
1820
  planner.min_travel_feedrate_mm_s = DEFAULT_MINTRAVELFEEDRATE;
1821
 
1822
  #if ENABLED(JUNCTION_DEVIATION)
1823
    planner.junction_deviation_mm = float(JUNCTION_DEVIATION_MM);
1824
  #else
1825
    #if ENABLED(HANGPRINTER)
1826
      planner.max_jerk[A_AXIS] = DEFAULT_AJERK;
1827
      planner.max_jerk[B_AXIS] = DEFAULT_BJERK;
1828
      planner.max_jerk[C_AXIS] = DEFAULT_CJERK;
1829
      planner.max_jerk[D_AXIS] = DEFAULT_DJERK;
1830
    #else
1831
      planner.max_jerk[X_AXIS] = DEFAULT_XJERK;
1832
      planner.max_jerk[Y_AXIS] = DEFAULT_YJERK;
1833
      planner.max_jerk[Z_AXIS] = DEFAULT_ZJERK;
1834
    #endif
1835
    planner.max_jerk[E_AXIS] = DEFAULT_EJERK;
1836
  #endif
1837
 
1838
  #if HAS_HOME_OFFSET
1839
    ZERO(home_offset);
1840
  #endif
1841
 
1842
  #if HOTENDS > 1
1843
    constexpr float tmp4[XYZ][HOTENDS] = {
1844
      HOTEND_OFFSET_X,
1845
      HOTEND_OFFSET_Y
1846
      #if HAS_HOTEND_OFFSET_Z
1847
        , HOTEND_OFFSET_Z
1848
      #else
1849
        , { 0 }
1850
      #endif
1851
    };
1852
    static_assert(
1853
      tmp4[X_AXIS][0] == 0 && tmp4[Y_AXIS][0] == 0 && tmp4[Z_AXIS][0] == 0,
1854
      "Offsets for the first hotend must be 0.0."
1855
    );
1856
    LOOP_XYZ(i) HOTEND_LOOP() hotend_offset[i][e] = tmp4[i][e];
1857
  #endif
1858
 
1859
  //
1860
  // Global Leveling
1861
  //
1862
 
1863
  #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
1864
    new_z_fade_height = 0.0;
1865
  #endif
1866
 
1867
  #if HAS_LEVELING
1868
    reset_bed_level();
1869
  #endif
1870
 
1871
  #if HAS_BED_PROBE
1872
    zprobe_zoffset = Z_PROBE_OFFSET_FROM_EXTRUDER;
1873
  #endif
1874
 
1875
  #if ENABLED(DELTA)
1876
    const float adj[ABC] = DELTA_ENDSTOP_ADJ,
1877
                dta[ABC] = DELTA_TOWER_ANGLE_TRIM;
1878
    delta_height = DELTA_HEIGHT;
1879
    COPY(delta_endstop_adj, adj);
1880
    delta_radius = DELTA_RADIUS;
1881
    delta_diagonal_rod = DELTA_DIAGONAL_ROD;
1882
    delta_segments_per_second = DELTA_SEGMENTS_PER_SECOND;
1883
    delta_calibration_radius = DELTA_CALIBRATION_RADIUS;
1884
    COPY(delta_tower_angle_trim, dta);
1885
 
1886
  #elif ENABLED(HANGPRINTER)
1887
 
1888
    anchor_A_y = float(ANCHOR_A_Y);
1889
    anchor_A_z = float(ANCHOR_A_Z);
1890
    anchor_B_x = float(ANCHOR_B_X);
1891
    anchor_B_y = float(ANCHOR_B_Y);
1892
    anchor_B_z = float(ANCHOR_B_Z);
1893
    anchor_C_x = float(ANCHOR_C_X);
1894
    anchor_C_y = float(ANCHOR_C_Y);
1895
    anchor_C_z = float(ANCHOR_C_Z);
1896
    anchor_D_z = float(ANCHOR_D_Z);
1897
    delta_segments_per_second = KINEMATIC_SEGMENTS_PER_SECOND;
1898
 
1899
  #elif ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
1900
 
1901
    #if ENABLED(X_DUAL_ENDSTOPS)
1902
      endstops.x_endstop_adj = (
1903
        #ifdef X_DUAL_ENDSTOPS_ADJUSTMENT
1904
          X_DUAL_ENDSTOPS_ADJUSTMENT
1905
        #else
1906
 
1907
        #endif
1908
      );
1909
    #endif
1910
    #if ENABLED(Y_DUAL_ENDSTOPS)
1911
      endstops.y_endstop_adj = (
1912
        #ifdef Y_DUAL_ENDSTOPS_ADJUSTMENT
1913
          Y_DUAL_ENDSTOPS_ADJUSTMENT
1914
        #else
1915
 
1916
        #endif
1917
      );
1918
    #endif
1919
    #if ENABLED(Z_DUAL_ENDSTOPS)
1920
      endstops.z_endstop_adj = (
1921
        #ifdef Z_DUAL_ENDSTOPS_ADJUSTMENT
1922
          Z_DUAL_ENDSTOPS_ADJUSTMENT
1923
        #else
1924
 
1925
        #endif
1926
      );
1927
    #endif
1928
  #endif
1929
 
1930
  #if ENABLED(ULTIPANEL)
1931
    lcd_preheat_hotend_temp[0] = PREHEAT_1_TEMP_HOTEND;
1932
    lcd_preheat_hotend_temp[1] = PREHEAT_2_TEMP_HOTEND;
1933
    lcd_preheat_bed_temp[0] = PREHEAT_1_TEMP_BED;
1934
    lcd_preheat_bed_temp[1] = PREHEAT_2_TEMP_BED;
1935
    lcd_preheat_fan_speed[0] = PREHEAT_1_FAN_SPEED;
1936
    lcd_preheat_fan_speed[1] = PREHEAT_2_FAN_SPEED;
1937
  #endif
1938
 
1939
  #if ENABLED(PIDTEMP)
1940
    #if ENABLED(PID_PARAMS_PER_HOTEND) && HOTENDS > 1
1941
      HOTEND_LOOP()
1942
    #endif
1943
    {
1944
      PID_PARAM(Kp, e) = float(DEFAULT_Kp);
1945
      PID_PARAM(Ki, e) = scalePID_i(DEFAULT_Ki);
1946
      PID_PARAM(Kd, e) = scalePID_d(DEFAULT_Kd);
1947
      #if ENABLED(PID_EXTRUSION_SCALING)
1948
        PID_PARAM(Kc, e) = DEFAULT_Kc;
1949
      #endif
1950
    }
1951
    #if ENABLED(PID_EXTRUSION_SCALING)
1952
      thermalManager.lpq_len = 20; // default last-position-queue size
1953
    #endif
1954
  #endif // PIDTEMP
1955
 
1956
  #if ENABLED(PIDTEMPBED)
1957
    thermalManager.bedKp = DEFAULT_bedKp;
1958
    thermalManager.bedKi = scalePID_i(DEFAULT_bedKi);
1959
    thermalManager.bedKd = scalePID_d(DEFAULT_bedKd);
1960
  #endif
1961
 
1962
  #if HAS_LCD_CONTRAST
1963
    lcd_contrast = DEFAULT_LCD_CONTRAST;
1964
  #endif
1965
 
1966
  #if ENABLED(FWRETRACT)
1967
    fwretract.reset();
1968
  #endif
1969
 
1970
  #if DISABLED(NO_VOLUMETRICS)
1971
 
1972
    parser.volumetric_enabled =
1973
      #if ENABLED(VOLUMETRIC_DEFAULT_ON)
1974
        true
1975
      #else
1976
        false
1977
      #endif
1978
    ;
1979
    for (uint8_t q = 0; q < COUNT(planner.filament_size); q++)
1980
      planner.filament_size[q] = DEFAULT_NOMINAL_FILAMENT_DIA;
1981
 
1982
  #endif
1983
 
1984
  endstops.enable_globally(
1985
    #if ENABLED(ENDSTOPS_ALWAYS_ON_DEFAULT)
1986
      true
1987
    #else
1988
      false
1989
    #endif
1990
  );
1991
 
1992
  reset_stepper_drivers();
1993
 
1994
  #if ENABLED(LIN_ADVANCE)
1995
    planner.extruder_advance_K = LIN_ADVANCE_K;
1996
  #endif
1997
 
1998
  #if HAS_MOTOR_CURRENT_PWM
1999
    uint32_t tmp_motor_current_setting[XYZ] = PWM_MOTOR_CURRENT;
2000
    for (uint8_t q = XYZ; q--;)
2001
      stepper.digipot_current(q, (stepper.motor_current_setting[q] = tmp_motor_current_setting[q]));
2002
  #endif
2003
 
2004
  #if ENABLED(SKEW_CORRECTION_GCODE)
2005
    planner.xy_skew_factor = XY_SKEW_FACTOR;
2006
    #if ENABLED(SKEW_CORRECTION_FOR_Z)
2007
      planner.xz_skew_factor = XZ_SKEW_FACTOR;
2008
      planner.yz_skew_factor = YZ_SKEW_FACTOR;
2009
    #endif
2010
  #endif
2011
 
2012
  #if ENABLED(ADVANCED_PAUSE_FEATURE)
2013
    for (uint8_t e = 0; e < EXTRUDERS; e++) {
2014
      filament_change_unload_length[e] = FILAMENT_CHANGE_UNLOAD_LENGTH;
2015
      filament_change_load_length[e] = FILAMENT_CHANGE_FAST_LOAD_LENGTH;
2016
    }
2017
  #endif
2018
 
2019
  postprocess();
2020
 
2021
  #if ENABLED(EEPROM_CHITCHAT)
2022
    SERIAL_ECHO_START();
2023
    SERIAL_ECHOLNPGM("Hardcoded Default Settings Loaded");
2024
  #endif
2025
}
2026
 
2027
#if DISABLED(DISABLE_M503)
2028
 
2029
  #define CONFIG_ECHO_START do{ if (!forReplay) SERIAL_ECHO_START(); }while(0)
2030
 
2031
  #if HAS_TRINAMIC
2032
    void say_M906() { SERIAL_ECHOPGM("  M906"); }
2033
    #if ENABLED(HYBRID_THRESHOLD)
2034
      void say_M913() { SERIAL_ECHOPGM("  M913"); }
2035
    #endif
2036
    #if ENABLED(SENSORLESS_HOMING)
2037
      void say_M914() { SERIAL_ECHOPGM("  M914"); }
2038
    #endif
2039
  #endif
2040
 
2041
  #if ENABLED(ADVANCED_PAUSE_FEATURE)
2042
    void say_M603() { SERIAL_ECHOPGM("  M603 "); }
2043
  #endif
2044
 
2045
  inline void say_units(const bool colon=false) {
2046
    serialprintPGM(
2047
      #if ENABLED(INCH_MODE_SUPPORT)
2048
        parser.linear_unit_factor != 1.0 ? PSTR(" (in)") :
2049
      #endif
2050
      PSTR(" (mm)")
2051
    );
2052
    if (colon) SERIAL_ECHOLNPGM(":");
2053
  }
2054
 
2055
  /**
2056
   * M503 - Report current settings in RAM
2057
   *
2058
   * Unless specifically disabled, M503 is available even without EEPROM
2059
   */
2060
  void MarlinSettings::report(const bool forReplay) {
2061
 
2062
    /**
2063
     * Announce current units, in case inches are being displayed
2064
     */
2065
    CONFIG_ECHO_START;
2066
    #if ENABLED(INCH_MODE_SUPPORT)
2067
      #define LINEAR_UNIT(N) (float(N) / parser.linear_unit_factor)
2068
      #define VOLUMETRIC_UNIT(N) (float(N) / (parser.volumetric_enabled ? parser.volumetric_unit_factor : parser.linear_unit_factor))
2069
      SERIAL_ECHOPGM("  G2");
2070
      SERIAL_CHAR(parser.linear_unit_factor == 1.0 ? '1' : '0');
2071
      SERIAL_ECHOPGM(" ;");
2072
      say_units();
2073
    #else
2074
      #define LINEAR_UNIT(N) (N)
2075
      #define VOLUMETRIC_UNIT(N) (N)
2076
      SERIAL_ECHOPGM("  G21    ;");
2077
      say_units();
2078
    #endif
2079
    SERIAL_EOL();
2080
 
2081
    #if ENABLED(ULTIPANEL)
2082
 
2083
      // Temperature units - for Ultipanel temperature options
2084
 
2085
      CONFIG_ECHO_START;
2086
      #if ENABLED(TEMPERATURE_UNITS_SUPPORT)
2087
        #define TEMP_UNIT(N) parser.to_temp_units(N)
2088
        SERIAL_ECHOPGM("  M149 ");
2089
        SERIAL_CHAR(parser.temp_units_code());
2090
        SERIAL_ECHOPGM(" ; Units in ");
2091
        serialprintPGM(parser.temp_units_name());
2092
      #else
2093
        #define TEMP_UNIT(N) (N)
2094
        SERIAL_ECHOLNPGM("  M149 C ; Units in Celsius");
2095
      #endif
2096
 
2097
    #endif
2098
 
2099
    SERIAL_EOL();
2100
 
2101
    #if DISABLED(NO_VOLUMETRICS)
2102
 
2103
      /**
2104
       * Volumetric extrusion M200
2105
       */
2106
      if (!forReplay) {
2107
        CONFIG_ECHO_START;
2108
        SERIAL_ECHOPGM("Filament settings:");
2109
        if (parser.volumetric_enabled)
2110
          SERIAL_EOL();
2111
        else
2112
          SERIAL_ECHOLNPGM(" Disabled");
2113
      }
2114
 
2115
      CONFIG_ECHO_START;
2116
      SERIAL_ECHOPAIR("  M200 D", LINEAR_UNIT(planner.filament_size[0]));
2117
      SERIAL_EOL();
2118
      #if EXTRUDERS > 1
2119
        CONFIG_ECHO_START;
2120
        SERIAL_ECHOPAIR("  M200 T1 D", LINEAR_UNIT(planner.filament_size[1]));
2121
        SERIAL_EOL();
2122
        #if EXTRUDERS > 2
2123
          CONFIG_ECHO_START;
2124
          SERIAL_ECHOPAIR("  M200 T2 D", LINEAR_UNIT(planner.filament_size[2]));
2125
          SERIAL_EOL();
2126
          #if EXTRUDERS > 3
2127
            CONFIG_ECHO_START;
2128
            SERIAL_ECHOPAIR("  M200 T3 D", LINEAR_UNIT(planner.filament_size[3]));
2129
            SERIAL_EOL();
2130
            #if EXTRUDERS > 4
2131
              CONFIG_ECHO_START;
2132
              SERIAL_ECHOPAIR("  M200 T4 D", LINEAR_UNIT(planner.filament_size[4]));
2133
              SERIAL_EOL();
2134
            #endif // EXTRUDERS > 4
2135
          #endif // EXTRUDERS > 3
2136
        #endif // EXTRUDERS > 2
2137
      #endif // EXTRUDERS > 1
2138
 
2139
      if (!parser.volumetric_enabled) {
2140
        CONFIG_ECHO_START;
2141
        SERIAL_ECHOLNPGM("  M200 D0");
2142
      }
2143
 
2144
    #endif // !NO_VOLUMETRICS
2145
 
2146
    if (!forReplay) {
2147
      CONFIG_ECHO_START;
2148
      SERIAL_ECHOLNPGM("Steps per unit:");
2149
    }
2150
    CONFIG_ECHO_START;
2151
    #if ENABLED(HANGPRINTER)
2152
      SERIAL_ECHOPAIR("  M92 A", LINEAR_UNIT(planner.axis_steps_per_mm[A_AXIS]));
2153
      SERIAL_ECHOPAIR(" B", LINEAR_UNIT(planner.axis_steps_per_mm[B_AXIS]));
2154
      SERIAL_ECHOPAIR(" C", LINEAR_UNIT(planner.axis_steps_per_mm[C_AXIS]));
2155
      SERIAL_ECHOPAIR(" D", LINEAR_UNIT(planner.axis_steps_per_mm[D_AXIS]));
2156
    #else
2157
      SERIAL_ECHOPAIR("  M92 X", LINEAR_UNIT(planner.axis_steps_per_mm[X_AXIS]));
2158
      SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(planner.axis_steps_per_mm[Y_AXIS]));
2159
      SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.axis_steps_per_mm[Z_AXIS]));
2160
    #endif
2161
    #if DISABLED(DISTINCT_E_FACTORS)
2162
      SERIAL_ECHOPAIR(" E", VOLUMETRIC_UNIT(planner.axis_steps_per_mm[E_AXIS]));
2163
    #endif
2164
    SERIAL_EOL();
2165
    #if ENABLED(DISTINCT_E_FACTORS)
2166
      CONFIG_ECHO_START;
2167
      for (uint8_t i = 0; i < E_STEPPERS; i++) {
2168
        SERIAL_ECHOPAIR("  M92 T", (int)i);
2169
        SERIAL_ECHOLNPAIR(" E", VOLUMETRIC_UNIT(planner.axis_steps_per_mm[E_AXIS + i]));
2170
      }
2171
    #endif
2172
 
2173
    if (!forReplay) {
2174
      CONFIG_ECHO_START;
2175
      SERIAL_ECHOLNPGM("Maximum feedrates (units/s):");
2176
    }
2177
    CONFIG_ECHO_START;
2178
    #if ENABLED(HANGPRINTER)
2179
      SERIAL_ECHOPAIR("  M203 A", LINEAR_UNIT(planner.max_feedrate_mm_s[A_AXIS]));
2180
      SERIAL_ECHOPAIR(" B", LINEAR_UNIT(planner.max_feedrate_mm_s[B_AXIS]));
2181
      SERIAL_ECHOPAIR(" C", LINEAR_UNIT(planner.max_feedrate_mm_s[C_AXIS]));
2182
      SERIAL_ECHOPAIR(" D", LINEAR_UNIT(planner.max_feedrate_mm_s[D_AXIS]));
2183
    #else
2184
      SERIAL_ECHOPAIR("  M203 X", LINEAR_UNIT(planner.max_feedrate_mm_s[X_AXIS]));
2185
      SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(planner.max_feedrate_mm_s[Y_AXIS]));
2186
      SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.max_feedrate_mm_s[Z_AXIS]));
2187
    #endif
2188
    #if DISABLED(DISTINCT_E_FACTORS)
2189
      SERIAL_ECHOPAIR(" E", VOLUMETRIC_UNIT(planner.max_feedrate_mm_s[E_AXIS]));
2190
    #endif
2191
    SERIAL_EOL();
2192
    #if ENABLED(DISTINCT_E_FACTORS)
2193
      CONFIG_ECHO_START;
2194
      for (uint8_t i = 0; i < E_STEPPERS; i++) {
2195
        SERIAL_ECHOPAIR("  M203 T", (int)i);
2196
        SERIAL_ECHOLNPAIR(" E", VOLUMETRIC_UNIT(planner.max_feedrate_mm_s[E_AXIS + i]));
2197
      }
2198
    #endif
2199
 
2200
    if (!forReplay) {
2201
      CONFIG_ECHO_START;
2202
      SERIAL_ECHOLNPGM("Maximum Acceleration (units/s2):");
2203
    }
2204
    CONFIG_ECHO_START;
2205
    #if ENABLED(HANGPRINTER)
2206
      SERIAL_ECHOPAIR("  M201 A", LINEAR_UNIT(planner.max_acceleration_mm_per_s2[A_AXIS]));
2207
      SERIAL_ECHOPAIR(" B", LINEAR_UNIT(planner.max_acceleration_mm_per_s2[B_AXIS]));
2208
      SERIAL_ECHOPAIR(" C", LINEAR_UNIT(planner.max_acceleration_mm_per_s2[C_AXIS]));
2209
      SERIAL_ECHOPAIR(" D", LINEAR_UNIT(planner.max_acceleration_mm_per_s2[D_AXIS]));
2210
    #else
2211
      SERIAL_ECHOPAIR("  M201 X", LINEAR_UNIT(planner.max_acceleration_mm_per_s2[X_AXIS]));
2212
      SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(planner.max_acceleration_mm_per_s2[Y_AXIS]));
2213
      SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.max_acceleration_mm_per_s2[Z_AXIS]));
2214
    #endif
2215
    #if DISABLED(DISTINCT_E_FACTORS)
2216
      SERIAL_ECHOPAIR(" E", VOLUMETRIC_UNIT(planner.max_acceleration_mm_per_s2[E_AXIS]));
2217
    #endif
2218
    SERIAL_EOL();
2219
    #if ENABLED(DISTINCT_E_FACTORS)
2220
      CONFIG_ECHO_START;
2221
      for (uint8_t i = 0; i < E_STEPPERS; i++) {
2222
        SERIAL_ECHOPAIR("  M201 T", (int)i);
2223
        SERIAL_ECHOLNPAIR(" E", VOLUMETRIC_UNIT(planner.max_acceleration_mm_per_s2[E_AXIS + i]));
2224
      }
2225
    #endif
2226
 
2227
    if (!forReplay) {
2228
      CONFIG_ECHO_START;
2229
      SERIAL_ECHOLNPGM("Acceleration (units/s2): P<print_accel> R<retract_accel> T<travel_accel>");
2230
    }
2231
    CONFIG_ECHO_START;
2232
    SERIAL_ECHOPAIR("  M204 P", LINEAR_UNIT(planner.acceleration));
2233
    SERIAL_ECHOPAIR(" R", LINEAR_UNIT(planner.retract_acceleration));
2234
    SERIAL_ECHOLNPAIR(" T", LINEAR_UNIT(planner.travel_acceleration));
2235
 
2236
    if (!forReplay) {
2237
      CONFIG_ECHO_START;
2238
      SERIAL_ECHOPGM("Advanced: Q<min_segment_time_us> S<min_feedrate> T<min_travel_feedrate>");
2239
      #if ENABLED(JUNCTION_DEVIATION)
2240
        SERIAL_ECHOPGM(" J<junc_dev>");
2241
      #else
2242
        #if ENABLED(HANGPRINTER)
2243
          SERIAL_ECHOPGM(" A<max_a_jerk> B<max_b_jerk> C<max_c_jerk> D<max_d_jerk>");
2244
        #else
2245
          SERIAL_ECHOPGM(" X<max_x_jerk> Y<max_y_jerk> Z<max_z_jerk>");
2246
        #endif
2247
      #endif
2248
      #if DISABLED(JUNCTION_DEVIATION) || ENABLED(LIN_ADVANCE)
2249
        SERIAL_ECHOPGM(" E<max_e_jerk>");
2250
      #endif
2251
      SERIAL_EOL();
2252
    }
2253
    CONFIG_ECHO_START;
2254
    SERIAL_ECHOPAIR("  M205 Q", LINEAR_UNIT(planner.min_segment_time_us));
2255
    SERIAL_ECHOPAIR(" S", LINEAR_UNIT(planner.min_feedrate_mm_s));
2256
    SERIAL_ECHOPAIR(" T", LINEAR_UNIT(planner.min_travel_feedrate_mm_s));
2257
 
2258
    #if ENABLED(JUNCTION_DEVIATION)
2259
      SERIAL_ECHOPAIR(" J", LINEAR_UNIT(planner.junction_deviation_mm));
2260
    #else
2261
      #if ENABLED(HANGPRINTER)
2262
        SERIAL_ECHOPAIR(" A", LINEAR_UNIT(planner.max_jerk[A_AXIS]));
2263
        SERIAL_ECHOPAIR(" B", LINEAR_UNIT(planner.max_jerk[B_AXIS]));
2264
        SERIAL_ECHOPAIR(" C", LINEAR_UNIT(planner.max_jerk[C_AXIS]));
2265
        SERIAL_ECHOPAIR(" D", LINEAR_UNIT(planner.max_jerk[D_AXIS]));
2266
      #else
2267
        SERIAL_ECHOPAIR(" X", LINEAR_UNIT(planner.max_jerk[X_AXIS]));
2268
        SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(planner.max_jerk[Y_AXIS]));
2269
        SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.max_jerk[Z_AXIS]));
2270
      #endif
2271
      SERIAL_ECHOPAIR(" E", LINEAR_UNIT(planner.max_jerk[E_AXIS]));
2272
    #endif
2273
    SERIAL_EOL();
2274
 
2275
    #if HAS_M206_COMMAND
2276
      if (!forReplay) {
2277
        CONFIG_ECHO_START;
2278
        SERIAL_ECHOLNPGM("Home offset:");
2279
      }
2280
      CONFIG_ECHO_START;
2281
      SERIAL_ECHOPAIR("  M206 X", LINEAR_UNIT(home_offset[X_AXIS]));
2282
      SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(home_offset[Y_AXIS]));
2283
      SERIAL_ECHOLNPAIR(" Z", LINEAR_UNIT(home_offset[Z_AXIS]));
2284
    #endif
2285
 
2286
    #if HOTENDS > 1
2287
      if (!forReplay) {
2288
        CONFIG_ECHO_START;
2289
        SERIAL_ECHOLNPGM("Hotend offsets:");
2290
      }
2291
      CONFIG_ECHO_START;
2292
      for (uint8_t e = 1; e < HOTENDS; e++) {
2293
        SERIAL_ECHOPAIR("  M218 T", (int)e);
2294
        SERIAL_ECHOPAIR(" X", LINEAR_UNIT(hotend_offset[X_AXIS][e]));
2295
        SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(hotend_offset[Y_AXIS][e]));
2296
        #if HAS_HOTEND_OFFSET_Z
2297
          SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(hotend_offset[Z_AXIS][e]));
2298
        #endif
2299
        SERIAL_EOL();
2300
      }
2301
    #endif
2302
 
2303
    /**
2304
     * Bed Leveling
2305
     */
2306
    #if HAS_LEVELING
2307
 
2308
      #if ENABLED(MESH_BED_LEVELING)
2309
 
2310
        if (!forReplay) {
2311
          CONFIG_ECHO_START;
2312
          SERIAL_ECHOLNPGM("Mesh Bed Leveling:");
2313
        }
2314
 
2315
      #elif ENABLED(AUTO_BED_LEVELING_UBL)
2316
 
2317
        if (!forReplay) {
2318
          CONFIG_ECHO_START;
2319
          ubl.echo_name();
2320
          SERIAL_ECHOLNPGM(":");
2321
        }
2322
 
2323
      #elif HAS_ABL
2324
 
2325
        if (!forReplay) {
2326
          CONFIG_ECHO_START;
2327
          SERIAL_ECHOLNPGM("Auto Bed Leveling:");
2328
        }
2329
 
2330
      #endif
2331
 
2332
      CONFIG_ECHO_START;
2333
      SERIAL_ECHOPAIR("  M420 S", planner.leveling_active ? 1 : 0);
2334
      #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
2335
        SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.z_fade_height));
2336
      #endif
2337
      SERIAL_EOL();
2338
 
2339
      #if ENABLED(MESH_BED_LEVELING)
2340
 
2341
        if (leveling_is_valid()) {
2342
          for (uint8_t py = 0; py < GRID_MAX_POINTS_Y; py++) {
2343
            for (uint8_t px = 0; px < GRID_MAX_POINTS_X; px++) {
2344
              CONFIG_ECHO_START;
2345
              SERIAL_ECHOPAIR("  G29 S3 X", (int)px + 1);
2346
              SERIAL_ECHOPAIR(" Y", (int)py + 1);
2347
              SERIAL_ECHOPGM(" Z");
2348
              SERIAL_ECHO_F(LINEAR_UNIT(mbl.z_values[px][py]), 5);
2349
              SERIAL_EOL();
2350
            }
2351
          }
2352
        }
2353
 
2354
      #elif ENABLED(AUTO_BED_LEVELING_UBL)
2355
 
2356
        if (!forReplay) {
2357
          SERIAL_EOL();
2358
          ubl.report_state();
2359
          SERIAL_ECHOLNPAIR("\nActive Mesh Slot: ", ubl.storage_slot);
2360
          SERIAL_ECHOPAIR("EEPROM can hold ", calc_num_meshes());
2361
          SERIAL_ECHOLNPGM(" meshes.\n");
2362
        }
2363
 
2364
      //ubl.report_current_mesh(PORTVAR_SOLO);   // This is too verbose for large mesh's.   A better (more terse)
2365
                                                 // solution needs to be found.
2366
      #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
2367
 
2368
        if (leveling_is_valid()) {
2369
          for (uint8_t py = 0; py < GRID_MAX_POINTS_Y; py++) {
2370
            for (uint8_t px = 0; px < GRID_MAX_POINTS_X; px++) {
2371
              CONFIG_ECHO_START;
2372
              SERIAL_ECHOPAIR("  G29 W I", (int)px);
2373
              SERIAL_ECHOPAIR(" J", (int)py);
2374
              SERIAL_ECHOPGM(" Z");
2375
              SERIAL_ECHO_F(LINEAR_UNIT(z_values[px][py]), 5);
2376
              SERIAL_EOL();
2377
            }
2378
          }
2379
        }
2380
 
2381
      #endif
2382
 
2383
    #endif // HAS_LEVELING
2384
 
2385
    #if ENABLED(DELTA)
2386
 
2387
      if (!forReplay) {
2388
        CONFIG_ECHO_START;
2389
        SERIAL_ECHOLNPGM("Endstop adjustment:");
2390
      }
2391
      CONFIG_ECHO_START;
2392
      SERIAL_ECHOPAIR("  M666 X", LINEAR_UNIT(delta_endstop_adj[X_AXIS]));
2393
      SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(delta_endstop_adj[Y_AXIS]));
2394
      SERIAL_ECHOLNPAIR(" Z", LINEAR_UNIT(delta_endstop_adj[Z_AXIS]));
2395
      if (!forReplay) {
2396
        CONFIG_ECHO_START;
2397
        SERIAL_ECHOLNPGM("Delta settings: L<diagonal_rod> R<radius> H<height> S<segments_per_s> B<calibration radius> XYZ<tower angle corrections>");
2398
      }
2399
      CONFIG_ECHO_START;
2400
      SERIAL_ECHOPAIR("  M665 L", LINEAR_UNIT(delta_diagonal_rod));
2401
      SERIAL_ECHOPAIR(" R", LINEAR_UNIT(delta_radius));
2402
      SERIAL_ECHOPAIR(" H", LINEAR_UNIT(delta_height));
2403
      SERIAL_ECHOPAIR(" S", delta_segments_per_second);
2404
      SERIAL_ECHOPAIR(" B", LINEAR_UNIT(delta_calibration_radius));
2405
      SERIAL_ECHOPAIR(" X", LINEAR_UNIT(delta_tower_angle_trim[A_AXIS]));
2406
      SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(delta_tower_angle_trim[B_AXIS]));
2407
      SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(delta_tower_angle_trim[C_AXIS]));
2408
      SERIAL_EOL();
2409
 
2410
    #elif ENABLED(HANGPRINTER)
2411
      if (!forReplay) {
2412
        CONFIG_ECHO_START;
2413
        SERIAL_ECHOLNPGM("Hangprinter settings: W<Ay> E<Az> R<Bx> T<By> Y<Bz> U<Cx> I<Cy> O<Cz> P<Dz> S<segments_per_s>");
2414
      }
2415
      CONFIG_ECHO_START;
2416
      SERIAL_ECHOPAIR("  M665 W", anchor_A_y);
2417
      SERIAL_ECHOPAIR(" E", anchor_A_z);
2418
      SERIAL_ECHOPAIR(" R", anchor_B_x);
2419
      SERIAL_ECHOPAIR(" T", anchor_B_y);
2420
      SERIAL_ECHOPAIR(" Y", anchor_B_z);
2421
      SERIAL_ECHOPAIR(" U", anchor_C_x);
2422
      SERIAL_ECHOPAIR(" I", anchor_C_y);
2423
      SERIAL_ECHOPAIR(" O", anchor_C_z);
2424
      SERIAL_ECHOPAIR(" P", anchor_D_z);
2425
      SERIAL_ECHOPAIR(" S", delta_segments_per_second);
2426
      SERIAL_EOL();
2427
 
2428
    #elif ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
2429
 
2430
      if (!forReplay) {
2431
        CONFIG_ECHO_START;
2432
        SERIAL_ECHOLNPGM("Endstop adjustment:");
2433
      }
2434
      CONFIG_ECHO_START;
2435
      SERIAL_ECHOPGM("  M666");
2436
      #if ENABLED(X_DUAL_ENDSTOPS)
2437
        SERIAL_ECHOPAIR(" X", LINEAR_UNIT(endstops.x_endstop_adj));
2438
      #endif
2439
      #if ENABLED(Y_DUAL_ENDSTOPS)
2440
        SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(endstops.y_endstop_adj));
2441
      #endif
2442
      #if ENABLED(Z_DUAL_ENDSTOPS)
2443
        SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(endstops.z_endstop_adj));
2444
      #endif
2445
      SERIAL_EOL();
2446
 
2447
    #endif // [XYZ]_DUAL_ENDSTOPS
2448
 
2449
    #if ENABLED(ULTIPANEL)
2450
      if (!forReplay) {
2451
        CONFIG_ECHO_START;
2452
        SERIAL_ECHOLNPGM("Material heatup parameters:");
2453
      }
2454
      for (uint8_t i = 0; i < COUNT(lcd_preheat_hotend_temp); i++) {
2455
        CONFIG_ECHO_START;
2456
        SERIAL_ECHOPAIR("  M145 S", (int)i);
2457
        SERIAL_ECHOPAIR(" H", TEMP_UNIT(lcd_preheat_hotend_temp[i]));
2458
        SERIAL_ECHOPAIR(" B", TEMP_UNIT(lcd_preheat_bed_temp[i]));
2459
        SERIAL_ECHOLNPAIR(" F", lcd_preheat_fan_speed[i]);
2460
      }
2461
    #endif // ULTIPANEL
2462
 
2463
    #if HAS_PID_HEATING
2464
 
2465
      if (!forReplay) {
2466
        CONFIG_ECHO_START;
2467
        SERIAL_ECHOLNPGM("PID settings:");
2468
      }
2469
      #if ENABLED(PIDTEMP)
2470
        #if HOTENDS > 1
2471
          if (forReplay) {
2472
            HOTEND_LOOP() {
2473
              CONFIG_ECHO_START;
2474
              SERIAL_ECHOPAIR("  M301 E", e);
2475
              SERIAL_ECHOPAIR(" P", PID_PARAM(Kp, e));
2476
              SERIAL_ECHOPAIR(" I", unscalePID_i(PID_PARAM(Ki, e)));
2477
              SERIAL_ECHOPAIR(" D", unscalePID_d(PID_PARAM(Kd, e)));
2478
              #if ENABLED(PID_EXTRUSION_SCALING)
2479
                SERIAL_ECHOPAIR(" C", PID_PARAM(Kc, e));
2480
                if (e == 0) SERIAL_ECHOPAIR(" L", thermalManager.lpq_len);
2481
              #endif
2482
              SERIAL_EOL();
2483
            }
2484
          }
2485
          else
2486
        #endif // HOTENDS > 1
2487
        // !forReplay || HOTENDS == 1
2488
        {
2489
          CONFIG_ECHO_START;
2490
          SERIAL_ECHOPAIR("  M301 P", PID_PARAM(Kp, 0)); // for compatibility with hosts, only echo values for E0
2491
          SERIAL_ECHOPAIR(" I", unscalePID_i(PID_PARAM(Ki, 0)));
2492
          SERIAL_ECHOPAIR(" D", unscalePID_d(PID_PARAM(Kd, 0)));
2493
          #if ENABLED(PID_EXTRUSION_SCALING)
2494
            SERIAL_ECHOPAIR(" C", PID_PARAM(Kc, 0));
2495
            SERIAL_ECHOPAIR(" L", thermalManager.lpq_len);
2496
          #endif
2497
          SERIAL_EOL();
2498
        }
2499
      #endif // PIDTEMP
2500
 
2501
      #if ENABLED(PIDTEMPBED)
2502
        CONFIG_ECHO_START;
2503
        SERIAL_ECHOPAIR("  M304 P", thermalManager.bedKp);
2504
        SERIAL_ECHOPAIR(" I", unscalePID_i(thermalManager.bedKi));
2505
        SERIAL_ECHOPAIR(" D", unscalePID_d(thermalManager.bedKd));
2506
        SERIAL_EOL();
2507
      #endif
2508
 
2509
    #endif // PIDTEMP || PIDTEMPBED
2510
 
2511
    #if HAS_LCD_CONTRAST
2512
      if (!forReplay) {
2513
        CONFIG_ECHO_START;
2514
        SERIAL_ECHOLNPGM("LCD Contrast:");
2515
      }
2516
      CONFIG_ECHO_START;
2517
      SERIAL_ECHOLNPAIR("  M250 C", lcd_contrast);
2518
    #endif
2519
 
2520
    #if ENABLED(FWRETRACT)
2521
 
2522
      if (!forReplay) {
2523
        CONFIG_ECHO_START;
2524
        SERIAL_ECHOLNPGM("Retract: S<length> F<units/m> Z<lift>");
2525
      }
2526
      CONFIG_ECHO_START;
2527
      SERIAL_ECHOPAIR("  M207 S", LINEAR_UNIT(fwretract.retract_length));
2528
      SERIAL_ECHOPAIR(" W", LINEAR_UNIT(fwretract.swap_retract_length));
2529
      SERIAL_ECHOPAIR(" F", MMS_TO_MMM(LINEAR_UNIT(fwretract.retract_feedrate_mm_s)));
2530
      SERIAL_ECHOLNPAIR(" Z", LINEAR_UNIT(fwretract.retract_zlift));
2531
 
2532
      if (!forReplay) {
2533
        CONFIG_ECHO_START;
2534
        SERIAL_ECHOLNPGM("Recover: S<length> F<units/m>");
2535
      }
2536
      CONFIG_ECHO_START;
2537
      SERIAL_ECHOPAIR("  M208 S", LINEAR_UNIT(fwretract.retract_recover_length));
2538
      SERIAL_ECHOPAIR(" W", LINEAR_UNIT(fwretract.swap_retract_recover_length));
2539
      SERIAL_ECHOLNPAIR(" F", MMS_TO_MMM(LINEAR_UNIT(fwretract.retract_recover_feedrate_mm_s)));
2540
 
2541
      if (!forReplay) {
2542
        CONFIG_ECHO_START;
2543
        SERIAL_ECHOLNPGM("Auto-Retract: S=0 to disable, 1 to interpret E-only moves as retract/recover");
2544
      }
2545
      CONFIG_ECHO_START;
2546
      SERIAL_ECHOLNPAIR("  M209 S", fwretract.autoretract_enabled ? 1 : 0);
2547
 
2548
    #endif // FWRETRACT
2549
 
2550
    /**
2551
     * Probe Offset
2552
     */
2553
    #if HAS_BED_PROBE
2554
      if (!forReplay) {
2555
        CONFIG_ECHO_START;
2556
        SERIAL_ECHOPGM("Z-Probe Offset");
2557
        say_units(true);
2558
      }
2559
      CONFIG_ECHO_START;
2560
      SERIAL_ECHOLNPAIR("  M851 Z", LINEAR_UNIT(zprobe_zoffset));
2561
    #endif
2562
 
2563
    /**
2564
     * Bed Skew Correction
2565
     */
2566
    #if ENABLED(SKEW_CORRECTION_GCODE)
2567
      if (!forReplay) {
2568
        CONFIG_ECHO_START;
2569
        SERIAL_ECHOLNPGM("Skew Factor: ");
2570
      }
2571
      CONFIG_ECHO_START;
2572
      #if ENABLED(SKEW_CORRECTION_FOR_Z)
2573
        SERIAL_ECHOPGM("  M852 I");
2574
        SERIAL_ECHO_F(LINEAR_UNIT(planner.xy_skew_factor), 6);
2575
        SERIAL_ECHOPGM(" J");
2576
        SERIAL_ECHO_F(LINEAR_UNIT(planner.xz_skew_factor), 6);
2577
        SERIAL_ECHOPGM(" K");
2578
        SERIAL_ECHO_F(LINEAR_UNIT(planner.yz_skew_factor), 6);
2579
        SERIAL_EOL();
2580
      #else
2581
        SERIAL_ECHOPGM("  M852 S");
2582
        SERIAL_ECHO_F(LINEAR_UNIT(planner.xy_skew_factor), 6);
2583
        SERIAL_EOL();
2584
      #endif
2585
    #endif
2586
 
2587
    #if HAS_TRINAMIC
2588
 
2589
      /**
2590
       * TMC2130 / TMC2208 stepper driver current
2591
       */
2592
      if (!forReplay) {
2593
        CONFIG_ECHO_START;
2594
        SERIAL_ECHOLNPGM("Stepper driver current:");
2595
      }
2596
      CONFIG_ECHO_START;
2597
      #if AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z)
2598
        say_M906();
2599
      #endif
2600
      #if AXIS_IS_TMC(X)
2601
        SERIAL_ECHOPAIR(" X", stepperX.getCurrent());
2602
      #endif
2603
      #if AXIS_IS_TMC(Y)
2604
        SERIAL_ECHOPAIR(" Y", stepperY.getCurrent());
2605
      #endif
2606
      #if AXIS_IS_TMC(Z)
2607
        SERIAL_ECHOPAIR(" Z", stepperZ.getCurrent());
2608
      #endif
2609
      #if AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z)
2610
        SERIAL_EOL();
2611
      #endif
2612
      #if AXIS_IS_TMC(X2) || AXIS_IS_TMC(Y2) || AXIS_IS_TMC(Z2)
2613
        say_M906();
2614
        SERIAL_ECHOPGM(" I1");
2615
      #endif
2616
      #if AXIS_IS_TMC(X2)
2617
        SERIAL_ECHOPAIR(" X", stepperX2.getCurrent());
2618
      #endif
2619
      #if AXIS_IS_TMC(Y2)
2620
        SERIAL_ECHOPAIR(" Y", stepperY2.getCurrent());
2621
      #endif
2622
      #if AXIS_IS_TMC(Z2)
2623
        SERIAL_ECHOPAIR(" Z", stepperZ2.getCurrent());
2624
      #endif
2625
      #if AXIS_IS_TMC(X2) || AXIS_IS_TMC(Y2) || AXIS_IS_TMC(Z2)
2626
        SERIAL_EOL();
2627
      #endif
2628
      #if AXIS_IS_TMC(E0)
2629
        say_M906();
2630
        SERIAL_ECHOLNPAIR(" T0 E", stepperE0.getCurrent());
2631
      #endif
2632
      #if E_STEPPERS > 1 && AXIS_IS_TMC(E1)
2633
        say_M906();
2634
        SERIAL_ECHOLNPAIR(" T1 E", stepperE1.getCurrent());
2635
      #endif
2636
      #if E_STEPPERS > 2 && AXIS_IS_TMC(E2)
2637
        say_M906();
2638
        SERIAL_ECHOLNPAIR(" T2 E", stepperE2.getCurrent());
2639
      #endif
2640
      #if E_STEPPERS > 3 && AXIS_IS_TMC(E3)
2641
        say_M906();
2642
        SERIAL_ECHOLNPAIR(" T3 E", stepperE3.getCurrent());
2643
      #endif
2644
      #if E_STEPPERS > 4 && AXIS_IS_TMC(E4)
2645
        say_M906();
2646
        SERIAL_ECHOLNPAIR(" T4 E", stepperE4.getCurrent());
2647
      #endif
2648
      SERIAL_EOL();
2649
 
2650
      /**
2651
       * TMC2130 / TMC2208 / TRAMS Hybrid Threshold
2652
       */
2653
      #if ENABLED(HYBRID_THRESHOLD)
2654
        if (!forReplay) {
2655
          CONFIG_ECHO_START;
2656
          SERIAL_ECHOLNPGM("Hybrid Threshold:");
2657
        }
2658
        CONFIG_ECHO_START;
2659
        #if AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z)
2660
          say_M913();
2661
        #endif
2662
        #if AXIS_IS_TMC(X)
2663
          SERIAL_ECHOPAIR(" X", TMC_GET_PWMTHRS(X, X));
2664
        #endif
2665
        #if AXIS_IS_TMC(Y)
2666
          SERIAL_ECHOPAIR(" Y", TMC_GET_PWMTHRS(Y, Y));
2667
        #endif
2668
        #if AXIS_IS_TMC(Z)
2669
          SERIAL_ECHOPAIR(" Z", TMC_GET_PWMTHRS(Z, Z));
2670
        #endif
2671
        #if AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z)
2672
          SERIAL_EOL();
2673
        #endif
2674
        #if AXIS_IS_TMC(X2) || AXIS_IS_TMC(Y2) || AXIS_IS_TMC(Z2)
2675
          say_M913();
2676
          SERIAL_ECHOPGM(" I1");
2677
        #endif
2678
        #if AXIS_IS_TMC(X2)
2679
          SERIAL_ECHOPAIR(" X", TMC_GET_PWMTHRS(X, X2));
2680
        #endif
2681
        #if AXIS_IS_TMC(Y2)
2682
          SERIAL_ECHOPAIR(" Y", TMC_GET_PWMTHRS(Y, Y2));
2683
        #endif
2684
        #if AXIS_IS_TMC(Z2)
2685
          SERIAL_ECHOPAIR(" Z", TMC_GET_PWMTHRS(Z, Z2));
2686
        #endif
2687
        #if AXIS_IS_TMC(X2) || AXIS_IS_TMC(Y2) || AXIS_IS_TMC(Z2)
2688
          SERIAL_EOL();
2689
        #endif
2690
        #if AXIS_IS_TMC(E0)
2691
          say_M913();
2692
          SERIAL_ECHOLNPAIR(" T0 E", TMC_GET_PWMTHRS(E, E0));
2693
        #endif
2694
        #if E_STEPPERS > 1 && AXIS_IS_TMC(E1)
2695
          say_M913();
2696
          SERIAL_ECHOLNPAIR(" T1 E", TMC_GET_PWMTHRS(E, E1));
2697
        #endif
2698
        #if E_STEPPERS > 2 && AXIS_IS_TMC(E2)
2699
          say_M913();
2700
          SERIAL_ECHOLNPAIR(" T2 E", TMC_GET_PWMTHRS(E, E2));
2701
        #endif
2702
        #if E_STEPPERS > 3 && AXIS_IS_TMC(E3)
2703
          say_M913();
2704
          SERIAL_ECHOLNPAIR(" T3 E", TMC_GET_PWMTHRS(E, E3));
2705
        #endif
2706
        #if E_STEPPERS > 4 && AXIS_IS_TMC(E4)
2707
          say_M913();
2708
          SERIAL_ECHOLNPAIR(" T4 E", TMC_GET_PWMTHRS(E, E4));
2709
        #endif
2710
        SERIAL_EOL();
2711
      #endif // HYBRID_THRESHOLD
2712
 
2713
      /**
2714
       * TMC2130 Sensorless homing thresholds
2715
       */
2716
      #if ENABLED(SENSORLESS_HOMING)
2717
        if (!forReplay) {
2718
          CONFIG_ECHO_START;
2719
          SERIAL_ECHOLNPGM("Sensorless homing threshold:");
2720
        }
2721
        CONFIG_ECHO_START;
2722
        #if X_SENSORLESS || Y_SENSORLESS || Z_SENSORLESS
2723
          say_M914();
2724
          #if X_SENSORLESS
2725
            SERIAL_ECHOPAIR(" X", stepperX.sgt());
2726
          #endif
2727
          #if Y_SENSORLESS
2728
            SERIAL_ECHOPAIR(" Y", stepperY.sgt());
2729
          #endif
2730
          #if Z_SENSORLESS
2731
            SERIAL_ECHOPAIR(" Z", stepperZ.sgt());
2732
          #endif
2733
          SERIAL_EOL();
2734
        #endif
2735
 
2736
        #define X2_SENSORLESS (defined(X_HOMING_SENSITIVITY) && AXIS_HAS_STALLGUARD(X2))
2737
        #define Y2_SENSORLESS (defined(Y_HOMING_SENSITIVITY) && AXIS_HAS_STALLGUARD(Y2))
2738
        #define Z2_SENSORLESS (defined(Z_HOMING_SENSITIVITY) && AXIS_HAS_STALLGUARD(Z2))
2739
        #if X2_SENSORLESS || Y2_SENSORLESS || Z2_SENSORLESS
2740
          say_M914();
2741
          SERIAL_ECHOPGM(" I1");
2742
          #if X2_SENSORLESS
2743
            SERIAL_ECHOPAIR(" X", stepperX2.sgt());
2744
          #endif
2745
          #if Y2_SENSORLESS
2746
            SERIAL_ECHOPAIR(" Y", stepperY2.sgt());
2747
          #endif
2748
          #if Z2_SENSORLESS
2749
            SERIAL_ECHOPAIR(" Z", stepperZ2.sgt());
2750
          #endif
2751
          SERIAL_EOL();
2752
        #endif
2753
 
2754
      #endif // SENSORLESS_HOMING
2755
 
2756
    #endif // HAS_TRINAMIC
2757
 
2758
    /**
2759
     * Linear Advance
2760
     */
2761
    #if ENABLED(LIN_ADVANCE)
2762
      if (!forReplay) {
2763
        CONFIG_ECHO_START;
2764
        SERIAL_ECHOLNPGM("Linear Advance:");
2765
      }
2766
      CONFIG_ECHO_START;
2767
      SERIAL_ECHOLNPAIR("  M900 K", planner.extruder_advance_K);
2768
    #endif
2769
 
2770
    #if HAS_MOTOR_CURRENT_PWM
2771
      CONFIG_ECHO_START;
2772
      if (!forReplay) {
2773
        SERIAL_ECHOLNPGM("Stepper motor currents:");
2774
        CONFIG_ECHO_START;
2775
      }
2776
      SERIAL_ECHOPAIR("  M907 X", stepper.motor_current_setting[0]);
2777
      SERIAL_ECHOPAIR(" Z", stepper.motor_current_setting[1]);
2778
      SERIAL_ECHOPAIR(" E", stepper.motor_current_setting[2]);
2779
      SERIAL_EOL();
2780
    #endif
2781
 
2782
    /**
2783
     * Advanced Pause filament load & unload lengths
2784
     */
2785
    #if ENABLED(ADVANCED_PAUSE_FEATURE)
2786
      if (!forReplay) {
2787
        CONFIG_ECHO_START;
2788
        SERIAL_ECHOLNPGM("Filament load/unload lengths:");
2789
      }
2790
      CONFIG_ECHO_START;
2791
      #if EXTRUDERS == 1
2792
        say_M603();
2793
        SERIAL_ECHOPAIR("L", LINEAR_UNIT(filament_change_load_length[0]));
2794
        SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[0]));
2795
      #else
2796
        say_M603();
2797
        SERIAL_ECHOPAIR("T0 L", LINEAR_UNIT(filament_change_load_length[0]));
2798
        SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[0]));
2799
        CONFIG_ECHO_START;
2800
        say_M603();
2801
        SERIAL_ECHOPAIR("T1 L", LINEAR_UNIT(filament_change_load_length[1]));
2802
        SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[1]));
2803
        #if EXTRUDERS > 2
2804
          CONFIG_ECHO_START;
2805
          say_M603();
2806
          SERIAL_ECHOPAIR("T2 L", LINEAR_UNIT(filament_change_load_length[2]));
2807
          SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[2]));
2808
          #if EXTRUDERS > 3
2809
            CONFIG_ECHO_START;
2810
            say_M603();
2811
            SERIAL_ECHOPAIR("T3 L", LINEAR_UNIT(filament_change_load_length[3]));
2812
            SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[3]));
2813
            #if EXTRUDERS > 4
2814
              CONFIG_ECHO_START;
2815
              say_M603();
2816
              SERIAL_ECHOPAIR("T4 L", LINEAR_UNIT(filament_change_load_length[4]));
2817
              SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[4]));
2818
            #endif // EXTRUDERS > 4
2819
          #endif // EXTRUDERS > 3
2820
        #endif // EXTRUDERS > 2
2821
      #endif // EXTRUDERS == 1
2822
    #endif // ADVANCED_PAUSE_FEATURE
2823
  }
2824
 
2825
#endif // !DISABLE_M503