ConfigurationStore.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. //! @file
  2. #include "Marlin.h"
  3. #include "planner.h"
  4. #include "temperature.h"
  5. #include "ultralcd.h"
  6. #include "ConfigurationStore.h"
  7. #include "Configuration_var.h"
  8. #ifdef MESH_BED_LEVELING
  9. #include "mesh_bed_leveling.h"
  10. #endif
  11. #ifdef TMC2130
  12. #include "tmc2130.h"
  13. #endif
  14. M500_conf cs;
  15. #define EEPROM_VERSION "V2"
  16. #ifdef EEPROM_SETTINGS
  17. void Config_StoreSettings()
  18. {
  19. strcpy(cs.version, EEPROM_VERSION);
  20. eeprom_update_block(reinterpret_cast<uint8_t*>(&cs), reinterpret_cast<uint8_t*>(EEPROM_M500_base), sizeof(cs));
  21. #ifdef TEMP_MODEL
  22. temp_model_save_settings();
  23. #endif
  24. SERIAL_ECHO_START;
  25. SERIAL_ECHOLNPGM("Settings Stored");
  26. }
  27. #endif //EEPROM_SETTINGS
  28. #ifndef DISABLE_M503
  29. void Config_PrintSettings(uint8_t level)
  30. { // Always have this function, even with EEPROM_SETTINGS disabled, the current values will be shown
  31. #ifdef TMC2130
  32. printf_P(PSTR(
  33. "%SSteps per unit:\n%S M92 X%.2f Y%.2f Z%.2f E%.2f\n"
  34. "%SUStep resolution: \n%S M350 X%d Y%d Z%d E%d\n"
  35. "%SMaximum feedrates - normal (mm/s):\n%S M203 X%.2f Y%.2f Z%.2f E%.2f\n"
  36. "%SMaximum feedrates - stealth (mm/s):\n%S M203 X%.2f Y%.2f Z%.2f E%.2f\n"
  37. "%SMaximum acceleration - normal (mm/s2):\n%S M201 X%lu Y%lu Z%lu E%lu\n"
  38. "%SMaximum acceleration - stealth (mm/s2):\n%S M201 X%lu Y%lu Z%lu E%lu\n"
  39. "%SAcceleration: P=print, R=retract, T=travel\n%S M204 P%.2f R%.2f T%.2f\n"
  40. "%SAdvanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum XY jerk (mm/s), Z=maximum Z jerk (mm/s), E=maximum E jerk (mm/s)\n%S M205 S%.2f T%.2f B%.2f X%.2f Y%.2f Z%.2f E%.2f\n"
  41. "%SHome offset (mm):\n%S M206 X%.2f Y%.2f Z%.2f\n"
  42. ),
  43. echomagic, echomagic, cs.axis_steps_per_unit[X_AXIS], cs.axis_steps_per_unit[Y_AXIS], cs.axis_steps_per_unit[Z_AXIS], cs.axis_steps_per_unit[E_AXIS],
  44. echomagic, echomagic, cs.axis_ustep_resolution[X_AXIS], cs.axis_ustep_resolution[Y_AXIS], cs.axis_ustep_resolution[Z_AXIS], cs.axis_ustep_resolution[E_AXIS],
  45. echomagic, echomagic, cs.max_feedrate_normal[X_AXIS], cs.max_feedrate_normal[Y_AXIS], cs.max_feedrate_normal[Z_AXIS], cs.max_feedrate_normal[E_AXIS],
  46. echomagic, echomagic, cs.max_feedrate_silent[X_AXIS], cs.max_feedrate_silent[Y_AXIS], cs.max_feedrate_silent[Z_AXIS], cs.max_feedrate_silent[E_AXIS],
  47. echomagic, echomagic, cs.max_acceleration_units_per_sq_second_normal[X_AXIS], cs.max_acceleration_units_per_sq_second_normal[Y_AXIS], cs.max_acceleration_units_per_sq_second_normal[Z_AXIS], cs.max_acceleration_units_per_sq_second_normal[E_AXIS],
  48. echomagic, echomagic, cs.max_acceleration_units_per_sq_second_silent[X_AXIS], cs.max_acceleration_units_per_sq_second_silent[Y_AXIS], cs.max_acceleration_units_per_sq_second_silent[Z_AXIS], cs.max_acceleration_units_per_sq_second_silent[E_AXIS],
  49. echomagic, echomagic, cs.acceleration, cs.retract_acceleration, cs.travel_acceleration,
  50. echomagic, echomagic, cs.minimumfeedrate, cs.mintravelfeedrate, cs.minsegmenttime, cs.max_jerk[X_AXIS], cs.max_jerk[Y_AXIS], cs.max_jerk[Z_AXIS], cs.max_jerk[E_AXIS],
  51. echomagic, echomagic, cs.add_homing[X_AXIS], cs.add_homing[Y_AXIS], cs.add_homing[Z_AXIS]
  52. #else //TMC2130
  53. printf_P(PSTR(
  54. "%SSteps per unit:\n%S M92 X%.2f Y%.2f Z%.2f E%.2f\n"
  55. "%SMaximum feedrates (mm/s):\n%S M203 X%.2f Y%.2f Z%.2f E%.2f\n"
  56. "%SMaximum acceleration (mm/s2):\n%S M201 X%lu Y%lu Z%lu E%lu\n"
  57. "%SAcceleration: P=print, R=retract, T=travel\n%S M204 P%.2f R%.2f T%.2f\n"
  58. "%SAdvanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum XY jerk (mm/s), Z=maximum Z jerk (mm/s), E=maximum E jerk (mm/s)\n%S M205 S%.2f T%.2f B%.2f X%.2f Y%.2f Z%.2f E%.2f\n"
  59. "%SHome offset (mm):\n%S M206 X%.2f Y%.2f Z%.2f\n"
  60. ),
  61. echomagic, echomagic, cs.axis_steps_per_unit[X_AXIS], cs.axis_steps_per_unit[Y_AXIS], cs.axis_steps_per_unit[Z_AXIS], cs.axis_steps_per_unit[E_AXIS],
  62. echomagic, echomagic, max_feedrate[X_AXIS], max_feedrate[Y_AXIS], max_feedrate[Z_AXIS], max_feedrate[E_AXIS],
  63. echomagic, echomagic, max_acceleration_units_per_sq_second[X_AXIS], max_acceleration_units_per_sq_second[Y_AXIS], max_acceleration_units_per_sq_second[Z_AXIS], max_acceleration_units_per_sq_second[E_AXIS],
  64. echomagic, echomagic, cs.acceleration, cs.retract_acceleration, cs.travel_acceleration,
  65. echomagic, echomagic, cs.minimumfeedrate, cs.mintravelfeedrate, cs.minsegmenttime, cs.max_jerk[X_AXIS], cs.max_jerk[Y_AXIS], cs.max_jerk[Z_AXIS], cs.max_jerk[E_AXIS],
  66. echomagic, echomagic, cs.add_homing[X_AXIS], cs.add_homing[Y_AXIS], cs.add_homing[Z_AXIS]
  67. #endif //TMC2130
  68. );
  69. #ifdef PIDTEMP
  70. printf_P(PSTR("%SPID settings:\n%S M301 P%.2f I%.2f D%.2f\n"),
  71. echomagic, echomagic, cs.Kp, unscalePID_i(cs.Ki), unscalePID_d(cs.Kd));
  72. #endif
  73. #ifdef PIDTEMPBED
  74. printf_P(PSTR("%SPID heatbed settings:\n%S M304 P%.2f I%.2f D%.2f\n"),
  75. echomagic, echomagic, cs.bedKp, unscalePID_i(cs.bedKi), unscalePID_d(cs.bedKd));
  76. #endif
  77. #ifdef FWRETRACT
  78. printf_P(PSTR(
  79. "%SRetract: S=Length (mm) F:Speed (mm/m) Z: ZLift (mm)\n%S M207 S%.2f F%.2f Z%.2f\n"
  80. "%SRecover: S=Extra length (mm) F:Speed (mm/m)\n%S M208 S%.2f F%.2f\n"
  81. "%SAuto-Retract: S=0 to disable, 1 to interpret extrude-only moves as retracts or recoveries\n%S M209 S%d\n"
  82. ),
  83. echomagic, echomagic, cs.retract_length, cs.retract_feedrate*60, cs.retract_zlift,
  84. echomagic, echomagic, cs.retract_recover_length, cs.retract_recover_feedrate*60,
  85. echomagic, echomagic, (cs.autoretract_enabled ? 1 : 0)
  86. );
  87. #if EXTRUDERS > 1
  88. printf_P(PSTR("%SMulti-extruder settings:\n%S Swap retract length (mm): %.2f\n%S Swap rec. addl. length (mm): %.2f\n"),
  89. echomagic, echomagic, retract_length_swap, echomagic, retract_recover_length_swap);
  90. #endif
  91. if (cs.volumetric_enabled) {
  92. printf_P(PSTR("%SFilament settings:\n%S M200 D%.2f\n"),
  93. echomagic, echomagic, cs.filament_size[0]);
  94. #if EXTRUDERS > 1
  95. printf_P(PSTR("%S M200 T1 D%.2f\n"),
  96. echomagic, echomagic, cs.filament_size[1]);
  97. #if EXTRUDERS > 2
  98. printf_P(PSTR("%S M200 T1 D%.2f\n"),
  99. echomagic, echomagic, cs.filament_size[2]);
  100. #endif
  101. #endif
  102. } else {
  103. printf_P(PSTR("%SFilament settings: Disabled\n"), echomagic);
  104. }
  105. #endif
  106. if (level >= 10) {
  107. #ifdef LIN_ADVANCE
  108. printf_P(PSTR("%SLinear advance settings:%S M900 K%.2f\n"),
  109. echomagic, echomagic, extruder_advance_K);
  110. #endif //LIN_ADVANCE
  111. }
  112. // Arc Interpolation Settings
  113. printf_P(PSTR(
  114. "%SArc Settings: P:Max length(mm) S:Min length (mm) N:Corrections R:Min segments F:Segments/sec.\n%S M214 P%.2f S%.2f N%d R%d F%d\n"),
  115. echomagic, echomagic, cs.mm_per_arc_segment, cs.min_mm_per_arc_segment, cs.n_arc_correction, cs.min_arc_segments, cs.arc_segments_per_sec);
  116. #ifdef TEMP_MODEL
  117. temp_model_report_settings();
  118. #endif
  119. }
  120. #endif
  121. #ifdef EEPROM_SETTINGS
  122. static_assert (EXTRUDERS == 1, "ConfigurationStore M500_conf not implemented for more extruders, fix filament_size array size.");
  123. static_assert (NUM_AXIS == 4, "ConfigurationStore M500_conf not implemented for more axis."
  124. "Fix axis_steps_per_unit max_feedrate_normal max_acceleration_units_per_sq_second_normal max_jerk max_feedrate_silent"
  125. " max_acceleration_units_per_sq_second_silent array size.");
  126. #ifdef ENABLE_AUTO_BED_LEVELING
  127. static_assert (false, "zprobe_zoffset was not initialized in printers in field to -(Z_PROBE_OFFSET_FROM_EXTRUDER), so it contains"
  128. "0.0, if this is not acceptable, increment EEPROM_VERSION to force use default_conf");
  129. #endif
  130. static_assert (sizeof(M500_conf) == 209, "sizeof(M500_conf) has changed, ensure that EEPROM_VERSION has been incremented, "
  131. "or if you added members in the end of struct, ensure that historically uninitialized values will be initialized."
  132. "If this is caused by change to more then 8bit processor, decide whether make this struct packed to save EEPROM,"
  133. "leave as it is to keep fast code, or reorder struct members to pack more tightly.");
  134. static const M500_conf default_conf PROGMEM =
  135. {
  136. EEPROM_VERSION,
  137. DEFAULT_AXIS_STEPS_PER_UNIT,
  138. DEFAULT_MAX_FEEDRATE,
  139. DEFAULT_MAX_ACCELERATION,
  140. DEFAULT_ACCELERATION,
  141. DEFAULT_RETRACT_ACCELERATION,
  142. DEFAULT_MINIMUMFEEDRATE,
  143. DEFAULT_MINTRAVELFEEDRATE,
  144. DEFAULT_MINSEGMENTTIME,
  145. {DEFAULT_XJERK, DEFAULT_YJERK, DEFAULT_ZJERK, DEFAULT_EJERK},
  146. {0,0,0},
  147. -(Z_PROBE_OFFSET_FROM_EXTRUDER),
  148. DEFAULT_Kp,
  149. DEFAULT_Ki*PID_dT,
  150. DEFAULT_Kd/PID_dT,
  151. DEFAULT_bedKp,
  152. DEFAULT_bedKi*PID_dT,
  153. DEFAULT_bedKd/PID_dT,
  154. 0,
  155. false,
  156. RETRACT_LENGTH,
  157. RETRACT_FEEDRATE,
  158. RETRACT_ZLIFT,
  159. RETRACT_RECOVER_LENGTH,
  160. RETRACT_RECOVER_FEEDRATE,
  161. false,
  162. {DEFAULT_NOMINAL_FILAMENT_DIA,
  163. #if EXTRUDERS > 1
  164. DEFAULT_NOMINAL_FILAMENT_DIA,
  165. #if EXTRUDERS > 2
  166. DEFAULT_NOMINAL_FILAMENT_DIA,
  167. #endif
  168. #endif
  169. },
  170. DEFAULT_MAX_FEEDRATE_SILENT,
  171. DEFAULT_MAX_ACCELERATION_SILENT,
  172. #ifdef TMC2130
  173. { TMC2130_USTEPS_XY, TMC2130_USTEPS_XY, TMC2130_USTEPS_Z, TMC2130_USTEPS_E },
  174. #else // TMC2130
  175. {16,16,16,16},
  176. #endif
  177. DEFAULT_TRAVEL_ACCELERATION,
  178. DEFAULT_MM_PER_ARC_SEGMENT,
  179. DEFAULT_MIN_MM_PER_ARC_SEGMENT,
  180. DEFAULT_N_ARC_CORRECTION,
  181. DEFAULT_MIN_ARC_SEGMENTS,
  182. DEFAULT_ARC_SEGMENTS_PER_SEC
  183. };
  184. static bool is_uninitialized(void* addr, uint8_t len)
  185. {
  186. while(len--)
  187. {
  188. if(reinterpret_cast<uint8_t*>(addr)[len] != 0xff)
  189. return false;
  190. }
  191. return true;
  192. }
  193. //! @brief Read M500 configuration
  194. //! @retval true Succeeded. Stored settings retrieved or default settings retrieved in case EEPROM has been erased.
  195. //! @retval false Failed. Default settings has been retrieved, because of older version or corrupted data.
  196. bool Config_RetrieveSettings()
  197. {
  198. bool previous_settings_retrieved = true;
  199. static const char ver[4] PROGMEM = EEPROM_VERSION;
  200. eeprom_read_block(reinterpret_cast<uint8_t*>(cs.version), reinterpret_cast<uint8_t*>(EEPROM_M500_base->version), sizeof(cs.version));
  201. // SERIAL_ECHOLN("Version: [" << ver << "] Stored version: [" << cs.version << "]");
  202. if (strncmp_P(ver, cs.version, sizeof(EEPROM_VERSION)) == 0) // version number match
  203. {
  204. eeprom_read_block(reinterpret_cast<uint8_t*>(&cs), reinterpret_cast<uint8_t*>(EEPROM_M500_base), sizeof(cs));
  205. calculate_extruder_multipliers();
  206. //if max_feedrate_silent and max_acceleration_units_per_sq_second_silent were never stored to eeprom, use default values:
  207. for (uint8_t i = 0; i < (sizeof(cs.max_feedrate_silent)/sizeof(cs.max_feedrate_silent[0])); ++i)
  208. {
  209. const uint32_t erased = 0xffffffff;
  210. if (is_uninitialized(&(cs.max_feedrate_silent[i]), sizeof(float))) {
  211. memcpy_P(&cs.max_feedrate_silent[i],&default_conf.max_feedrate_silent[i], sizeof(cs.max_feedrate_silent[i]));
  212. }
  213. if (erased == cs.max_acceleration_units_per_sq_second_silent[i]) {
  214. memcpy_P(&cs.max_acceleration_units_per_sq_second_silent[i],&default_conf.max_acceleration_units_per_sq_second_silent[i],sizeof(cs.max_acceleration_units_per_sq_second_silent[i]));
  215. }
  216. }
  217. // Initialize arc interpolation settings if they are not already
  218. if (is_uninitialized(&cs.mm_per_arc_segment, sizeof(cs.mm_per_arc_segment))) cs.mm_per_arc_segment = default_conf.mm_per_arc_segment;
  219. if (is_uninitialized(&cs.min_mm_per_arc_segment, sizeof(cs.min_mm_per_arc_segment))) cs.min_mm_per_arc_segment = default_conf.min_mm_per_arc_segment;
  220. if (is_uninitialized(&cs.n_arc_correction, sizeof(cs.n_arc_correction))) cs.n_arc_correction = default_conf.n_arc_correction;
  221. if (is_uninitialized(&cs.min_arc_segments, sizeof(cs.min_arc_segments))) cs.min_arc_segments = default_conf.min_arc_segments;
  222. if (is_uninitialized(&cs.arc_segments_per_sec, sizeof(cs.arc_segments_per_sec))) cs.arc_segments_per_sec = default_conf.arc_segments_per_sec;
  223. #ifdef TMC2130
  224. for (uint8_t j = X_AXIS; j <= Y_AXIS; j++)
  225. {
  226. if (cs.max_feedrate_normal[j] > NORMAL_MAX_FEEDRATE_XY)
  227. cs.max_feedrate_normal[j] = NORMAL_MAX_FEEDRATE_XY;
  228. if (cs.max_feedrate_silent[j] > SILENT_MAX_FEEDRATE_XY)
  229. cs.max_feedrate_silent[j] = SILENT_MAX_FEEDRATE_XY;
  230. if (cs.max_acceleration_units_per_sq_second_normal[j] > NORMAL_MAX_ACCEL_XY)
  231. cs.max_acceleration_units_per_sq_second_normal[j] = NORMAL_MAX_ACCEL_XY;
  232. if (cs.max_acceleration_units_per_sq_second_silent[j] > SILENT_MAX_ACCEL_XY)
  233. cs.max_acceleration_units_per_sq_second_silent[j] = SILENT_MAX_ACCEL_XY;
  234. }
  235. if(cs.axis_ustep_resolution[X_AXIS] == 0xff){ cs.axis_ustep_resolution[X_AXIS] = TMC2130_USTEPS_XY; }
  236. if(cs.axis_ustep_resolution[Y_AXIS] == 0xff){ cs.axis_ustep_resolution[Y_AXIS] = TMC2130_USTEPS_XY; }
  237. if(cs.axis_ustep_resolution[Z_AXIS] == 0xff){ cs.axis_ustep_resolution[Z_AXIS] = TMC2130_USTEPS_Z; }
  238. if(cs.axis_ustep_resolution[E_AXIS] == 0xff){ cs.axis_ustep_resolution[E_AXIS] = TMC2130_USTEPS_E; }
  239. tmc2130_set_res(X_AXIS, cs.axis_ustep_resolution[X_AXIS]);
  240. tmc2130_set_res(Y_AXIS, cs.axis_ustep_resolution[Y_AXIS]);
  241. tmc2130_set_res(Z_AXIS, cs.axis_ustep_resolution[Z_AXIS]);
  242. tmc2130_set_res(E_AXIS, cs.axis_ustep_resolution[E_AXIS]);
  243. #endif //TMC2130
  244. if(is_uninitialized(&cs.travel_acceleration, sizeof(cs.travel_acceleration)))
  245. cs.travel_acceleration = cs.acceleration;
  246. reset_acceleration_rates();
  247. // Call updatePID (similar to when we have processed M301)
  248. updatePID();
  249. #ifdef TEMP_MODEL
  250. temp_model_load_settings();
  251. #endif
  252. SERIAL_ECHO_START;
  253. SERIAL_ECHOLNPGM("Stored settings retrieved");
  254. }
  255. else
  256. {
  257. Config_ResetDefault();
  258. //Return false to inform user that eeprom version was changed and firmware is using default hardcoded settings now.
  259. //In case that storing to eeprom was not used yet, do not inform user that hardcoded settings are used.
  260. if (eeprom_read_byte(reinterpret_cast<uint8_t*>(&(EEPROM_M500_base->version[0]))) != 0xFF ||
  261. eeprom_read_byte(reinterpret_cast<uint8_t*>(&(EEPROM_M500_base->version[1]))) != 0xFF ||
  262. eeprom_read_byte(reinterpret_cast<uint8_t*>(&(EEPROM_M500_base->version[2]))) != 0xFF)
  263. {
  264. previous_settings_retrieved = false;
  265. }
  266. }
  267. return previous_settings_retrieved;
  268. }
  269. #endif
  270. void Config_ResetDefault()
  271. {
  272. memcpy_P(&cs,&default_conf, sizeof(cs));
  273. // steps per sq second need to be updated to agree with the units per sq second
  274. reset_acceleration_rates();
  275. #ifdef PIDTEMP
  276. updatePID();
  277. #endif//PIDTEMP
  278. #ifdef TEMP_MODEL
  279. temp_model_reset_settings();
  280. #endif
  281. calculate_extruder_multipliers();
  282. SERIAL_ECHO_START;
  283. SERIAL_ECHOLNPGM("Hardcoded Default Settings Loaded");
  284. }