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