ConfigurationStore.cpp 14 KB

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