ConfigurationStore.cpp 15 KB

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