My Marlin configs for Fabrikator Mini and CTC i3 Pro B
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

M916-918.cpp 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. /**
  2. * Marlin 3D Printer Firmware
  3. * Copyright (c) 2019 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. // NOTE: All tests assume each axis uses matching driver chips.
  24. //
  25. #include "../../../inc/MarlinConfig.h"
  26. #if HAS_L64XX
  27. #include "../../gcode.h"
  28. #include "../../../module/stepper/indirection.h"
  29. #include "../../../module/planner.h"
  30. #include "../../../libs/L64XX/L64XX_Marlin.h"
  31. #define DEBUG_OUT ENABLED(L6470_CHITCHAT)
  32. #include "../../../core/debug_out.h"
  33. /**
  34. *
  35. * M916: increase KVAL_HOLD until get thermal warning
  36. * NOTE - on L6474 it is TVAL that is used
  37. *
  38. * J - select which driver(s) to monitor on multi-driver axis
  39. * 0 - (default) monitor all drivers on the axis or E0
  40. * 1 - monitor only X, Y, Z, E1
  41. * 2 - monitor only X2, Y2, Z2, E2
  42. * 3 - monitor only Z3, E3
  43. * 4 - monitor only Z4, E4
  44. *
  45. * Xxxx, Yxxx, Zxxx, Exxx - axis to be monitored with displacement
  46. * xxx (1-255) is distance moved on either side of current position
  47. *
  48. * F - feedrate
  49. * optional - will use default max feedrate from configuration.h if not specified
  50. *
  51. * T - current (mA) setting for TVAL (0 - 4A in 31.25mA increments, rounds down) - L6474 only
  52. * optional - will report current value from driver if not specified
  53. *
  54. * K - value for KVAL_HOLD (0 - 255) (ignored for L6474)
  55. * optional - will report current value from driver if not specified
  56. *
  57. * D - time (in seconds) to run each setting of KVAL_HOLD/TVAL
  58. * optional - defaults to zero (runs each setting once)
  59. *
  60. */
  61. /**
  62. * This routine is also useful for determining the approximate KVAL_HOLD
  63. * where the stepper stops losing steps. The sound will get noticeably quieter
  64. * as it stops losing steps.
  65. */
  66. void GcodeSuite::M916() {
  67. DEBUG_ECHOLNPGM("M916");
  68. L64xxManager.pause_monitor(true); // Keep monitor_driver() from stealing status
  69. // Variables used by L64xxManager.get_user_input function - some may not be used
  70. char axis_mon[3][3] = { {" "}, {" "}, {" "} }; // list of Axes to be monitored
  71. L64XX_axis_t axis_index[3];
  72. uint16_t axis_status[3];
  73. uint8_t driver_count = 1;
  74. float position_max;
  75. float position_min;
  76. float final_feedrate;
  77. uint8_t kval_hold;
  78. uint8_t OCD_TH_val = 0;
  79. uint8_t STALL_TH_val = 0;
  80. uint16_t over_current_threshold;
  81. constexpr uint8_t over_current_flag = false; // M916 doesn't play with the overcurrent thresholds
  82. #define DRIVER_TYPE_L6474(Q) AXIS_DRIVER_TYPE_##Q(L6474)
  83. uint8_t j; // general purpose counter
  84. if (L64xxManager.get_user_input(driver_count, axis_index, axis_mon, position_max, position_min, final_feedrate, kval_hold, over_current_flag, OCD_TH_val, STALL_TH_val, over_current_threshold))
  85. return; // quit if invalid user input
  86. DEBUG_ECHOLNPAIR("feedrate = ", final_feedrate);
  87. planner.synchronize(); // wait for all current movement commands to complete
  88. const L64XX_Marlin::L64XX_shadow_t &sh = L64xxManager.shadow;
  89. for (j = 0; j < driver_count; j++)
  90. L64xxManager.get_status(axis_index[j]); // clear out any pre-existing error flags
  91. char temp_axis_string[] = " ";
  92. temp_axis_string[0] = axis_mon[0][0]; // need to have a string for use within sprintf format section
  93. char gcode_string[80];
  94. uint16_t status_composite = 0;
  95. uint16_t M91x_counter = kval_hold;
  96. uint16_t M91x_counter_max;
  97. if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) {
  98. M91x_counter_max = 128; // TVAL is 7 bits
  99. LIMIT(M91x_counter, 0U, 127U);
  100. }
  101. else
  102. M91x_counter_max = 256; // KVAL_HOLD is 8 bits
  103. uint8_t M91x_delay_s = parser.byteval('D'); // get delay in seconds
  104. millis_t M91x_delay_ms = M91x_delay_s * 60 * 1000;
  105. millis_t M91x_delay_end;
  106. DEBUG_ECHOLNPGM(".\n.");
  107. do {
  108. if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT)
  109. DEBUG_ECHOLNPAIR("TVAL current (mA) = ", (M91x_counter + 1) * sh.AXIS_STALL_CURRENT_CONSTANT_INV); // report TVAL current for this run
  110. else
  111. DEBUG_ECHOLNPAIR("kval_hold = ", M91x_counter); // report KVAL_HOLD for this run
  112. for (j = 0; j < driver_count; j++)
  113. L64xxManager.set_param(axis_index[j], L6470_KVAL_HOLD, M91x_counter); //set KVAL_HOLD or TVAL (same register address)
  114. M91x_delay_end = millis() + M91x_delay_ms;
  115. do {
  116. // turn the motor(s) both directions
  117. sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_min), uint16_t(final_feedrate));
  118. gcode.process_subcommands_now_P(gcode_string);
  119. sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_max), uint16_t(final_feedrate));
  120. gcode.process_subcommands_now_P(gcode_string);
  121. // get the status after the motors have stopped
  122. planner.synchronize();
  123. status_composite = 0; // clear out the old bits
  124. for (j = 0; j < driver_count; j++) {
  125. axis_status[j] = (~L64xxManager.get_status(axis_index[j])) & sh.L6470_ERROR_MASK; // bits of interest are all active low
  126. status_composite |= axis_status[j] ;
  127. }
  128. if (status_composite) break;
  129. } while (millis() < M91x_delay_end);
  130. if (status_composite) break;
  131. M91x_counter++;
  132. } while (!(status_composite & (sh.STATUS_AXIS_TH_WRN | sh.STATUS_AXIS_TH_SD)) && (M91x_counter < M91x_counter_max));
  133. DEBUG_ECHOLNPGM(".");
  134. #if ENABLED(L6470_CHITCHAT)
  135. if (status_composite) {
  136. L64xxManager.error_status_decode(status_composite, axis_index[0],
  137. sh.STATUS_AXIS_TH_SD, sh.STATUS_AXIS_TH_WRN,
  138. sh.STATUS_AXIS_STEP_LOSS_A, sh.STATUS_AXIS_STEP_LOSS_B,
  139. sh.STATUS_AXIS_OCD, sh.STATUS_AXIS_LAYOUT);
  140. DEBUG_ECHOLNPGM(".");
  141. }
  142. #endif
  143. if ((status_composite & (sh.STATUS_AXIS_TH_WRN | sh.STATUS_AXIS_TH_SD)))
  144. DEBUG_ECHOLNPGM(".\n.\nTest completed normally - Thermal warning/shutdown has occurred");
  145. else if (status_composite)
  146. DEBUG_ECHOLNPGM(".\n.\nTest completed abnormally - non-thermal error has occured");
  147. else
  148. DEBUG_ECHOLNPGM(".\n.\nTest completed normally - Unable to get to thermal warning/shutdown");
  149. L64xxManager.pause_monitor(false);
  150. }
  151. /**
  152. *
  153. * M917: Find minimum current thresholds
  154. *
  155. * Decrease OCD current until overcurrent error
  156. * Increase OCD until overcurrent error goes away
  157. * Decrease stall threshold until stall (not done on L6474)
  158. * Increase stall until stall error goes away (not done on L6474)
  159. *
  160. * J - select which driver(s) to monitor on multi-driver axis
  161. * 0 - (default) monitor all drivers on the axis or E0
  162. * 1 - monitor only X, Y, Z, E1
  163. * 2 - monitor only X2, Y2, Z2, E2
  164. * Xxxx, Yxxx, Zxxx, Exxx - axis to be monitored with displacement
  165. * xxx (1-255) is distance moved on either side of current position
  166. *
  167. * F - feedrate
  168. * optional - will use default max feedrate from Configuration.h if not specified
  169. *
  170. * I - starting over-current threshold
  171. * optional - will report current value from driver if not specified
  172. * if there are multiple drivers on the axis then all will be set the same
  173. *
  174. * T - current (mA) setting for TVAL (0 - 4A in 31.25mA increments, rounds down) - L6474 only
  175. * optional - will report current value from driver if not specified
  176. *
  177. * K - value for KVAL_HOLD (0 - 255) (ignored for L6474)
  178. * optional - will report current value from driver if not specified
  179. *
  180. */
  181. void GcodeSuite::M917() {
  182. DEBUG_ECHOLNPGM("M917");
  183. L64xxManager.pause_monitor(true); // Keep monitor_driver() from stealing status
  184. char axis_mon[3][3] = { {" "}, {" "}, {" "} }; // list of Axes to be monitored
  185. L64XX_axis_t axis_index[3];
  186. uint16_t axis_status[3];
  187. uint8_t driver_count = 1;
  188. float position_max;
  189. float position_min;
  190. float final_feedrate;
  191. uint8_t kval_hold;
  192. uint8_t OCD_TH_val = 0;
  193. uint8_t STALL_TH_val = 0;
  194. uint16_t over_current_threshold;
  195. constexpr uint8_t over_current_flag = true;
  196. uint8_t j; // general purpose counter
  197. if (L64xxManager.get_user_input(driver_count, axis_index, axis_mon, position_max, position_min, final_feedrate, kval_hold, over_current_flag, OCD_TH_val, STALL_TH_val, over_current_threshold))
  198. return; // quit if invalid user input
  199. DEBUG_ECHOLNPAIR("feedrate = ", final_feedrate);
  200. planner.synchronize(); // wait for all current movement commands to complete
  201. const L64XX_Marlin::L64XX_shadow_t &sh = L64xxManager.shadow;
  202. for (j = 0; j < driver_count; j++)
  203. L64xxManager.get_status(axis_index[j]); // clear error flags
  204. char temp_axis_string[] = " ";
  205. temp_axis_string[0] = axis_mon[0][0]; // need a sprintf format string
  206. char gcode_string[80];
  207. uint16_t status_composite = 0;
  208. uint8_t test_phase = 0; // 0 - decreasing OCD - exit when OCD warning occurs (ignore STALL)
  209. // 1 - increasing OCD - exit when OCD warning stops (ignore STALL)
  210. // 2 - OCD finalized - decreasing STALL - exit when STALL warning happens
  211. // 3 - OCD finalized - increasing STALL - exit when STALL warning stop
  212. // 4 - all testing completed
  213. DEBUG_ECHOPAIR(".\n.\n.\nover_current threshold : ", (OCD_TH_val + 1) * 375); // first status display
  214. DEBUG_ECHOPAIR(" (OCD_TH: : ", OCD_TH_val);
  215. if (sh.STATUS_AXIS_LAYOUT != L6474_STATUS_LAYOUT) {
  216. DEBUG_ECHOPAIR(") Stall threshold: ", (STALL_TH_val + 1) * 31.25);
  217. DEBUG_ECHOPAIR(" (STALL_TH: ", STALL_TH_val);
  218. }
  219. DEBUG_ECHOLNPGM(")");
  220. do {
  221. if (sh.STATUS_AXIS_LAYOUT != L6474_STATUS_LAYOUT) DEBUG_ECHOPAIR("STALL threshold : ", (STALL_TH_val + 1) * 31.25);
  222. DEBUG_ECHOLNPAIR(" OCD threshold : ", (OCD_TH_val + 1) * 375);
  223. sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_min), uint16_t(final_feedrate));
  224. gcode.process_subcommands_now_P(gcode_string);
  225. sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_max), uint16_t(final_feedrate));
  226. gcode.process_subcommands_now_P(gcode_string);
  227. planner.synchronize();
  228. status_composite = 0; // clear out the old bits
  229. for (j = 0; j < driver_count; j++) {
  230. axis_status[j] = (~L64xxManager.get_status(axis_index[j])) & sh.L6470_ERROR_MASK; // bits of interest are all active low
  231. status_composite |= axis_status[j];
  232. }
  233. if (status_composite && (status_composite & sh.STATUS_AXIS_UVLO)) {
  234. DEBUG_ECHOLNPGM("Test aborted (Undervoltage lockout active)");
  235. #if ENABLED(L6470_CHITCHAT)
  236. for (j = 0; j < driver_count; j++) {
  237. if (j) DEBUG_ECHOPGM("...");
  238. L64xxManager.error_status_decode(axis_status[j], axis_index[j],
  239. sh.STATUS_AXIS_TH_SD, sh.STATUS_AXIS_TH_WRN,
  240. sh.STATUS_AXIS_STEP_LOSS_A, sh.STATUS_AXIS_STEP_LOSS_B,
  241. sh.STATUS_AXIS_OCD, sh.STATUS_AXIS_LAYOUT);
  242. }
  243. #endif
  244. return;
  245. }
  246. if (status_composite & (sh.STATUS_AXIS_TH_WRN | sh.STATUS_AXIS_TH_SD)) {
  247. DEBUG_ECHOLNPGM("thermal problem - waiting for chip(s) to cool down ");
  248. uint16_t status_composite_temp = 0;
  249. uint8_t k = 0;
  250. do {
  251. k++;
  252. if (!(k % 4)) {
  253. kval_hold *= 0.95;
  254. DEBUG_EOL();
  255. DEBUG_ECHOLNPAIR("Lowering KVAL_HOLD by about 5% to ", kval_hold);
  256. for (j = 0; j < driver_count; j++)
  257. L64xxManager.set_param(axis_index[j], L6470_KVAL_HOLD, kval_hold);
  258. }
  259. DEBUG_ECHOLNPGM(".");
  260. gcode.reset_stepper_timeout(); // reset_stepper_timeout to keep steppers powered
  261. watchdog_refresh();; // beat the dog
  262. safe_delay(5000);
  263. status_composite_temp = 0;
  264. for (j = 0; j < driver_count; j++) {
  265. axis_status[j] = (~L64xxManager.get_status(axis_index[j])) & sh.L6470_ERROR_MASK; // bits of interest are all active low
  266. status_composite_temp |= axis_status[j];
  267. }
  268. }
  269. while (status_composite_temp & (sh.STATUS_AXIS_TH_WRN | sh.STATUS_AXIS_TH_SD));
  270. DEBUG_EOL();
  271. }
  272. if (status_composite & (sh.STATUS_AXIS_STEP_LOSS_A | sh.STATUS_AXIS_STEP_LOSS_B | sh.STATUS_AXIS_OCD)) {
  273. switch (test_phase) {
  274. case 0: {
  275. if (status_composite & sh.STATUS_AXIS_OCD) {
  276. // phase 0 with OCD warning - time to go to next phase
  277. if (OCD_TH_val >= sh.AXIS_OCD_TH_MAX) {
  278. OCD_TH_val = sh.AXIS_OCD_TH_MAX; // limit to max
  279. test_phase = 2; // at highest value so skip phase 1
  280. //DEBUG_ECHOLNPGM("LOGIC E0A OCD at highest - skip to 2");
  281. DEBUG_ECHOLNPGM("OCD at highest - OCD finalized");
  282. }
  283. else {
  284. OCD_TH_val++; // normal exit to next phase
  285. test_phase = 1; // setup for first pass of phase 1
  286. //DEBUG_ECHOLNPGM("LOGIC E0B - inc OCD & go to 1");
  287. DEBUG_ECHOLNPGM("inc OCD");
  288. }
  289. }
  290. else { // phase 0 without OCD warning - keep on decrementing if can
  291. if (OCD_TH_val) {
  292. OCD_TH_val--; // try lower value
  293. //DEBUG_ECHOLNPGM("LOGIC E0C - dec OCD");
  294. DEBUG_ECHOLNPGM("dec OCD");
  295. }
  296. else {
  297. test_phase = 2; // at lowest value without warning so skip phase 1
  298. //DEBUG_ECHOLNPGM("LOGIC E0D - OCD at latest - go to 2");
  299. DEBUG_ECHOLNPGM("OCD finalized");
  300. }
  301. }
  302. } break;
  303. case 1: {
  304. if (status_composite & sh.STATUS_AXIS_OCD) {
  305. // phase 1 with OCD warning - increment if can
  306. if (OCD_TH_val >= sh.AXIS_OCD_TH_MAX) {
  307. OCD_TH_val = sh.AXIS_OCD_TH_MAX; // limit to max
  308. test_phase = 2; // at highest value so go to next phase
  309. //DEBUG_ECHOLNPGM("LOGIC E1A - OCD at max - go to 2");
  310. DEBUG_ECHOLNPGM("OCD finalized");
  311. }
  312. else {
  313. OCD_TH_val++; // try a higher value
  314. //DEBUG_ECHOLNPGM("LOGIC E1B - inc OCD");
  315. DEBUG_ECHOLNPGM("inc OCD");
  316. }
  317. }
  318. else { // phase 1 without OCD warning - normal exit to phase 2
  319. test_phase = 2;
  320. //DEBUG_ECHOLNPGM("LOGIC E1C - no OCD warning - go to 1");
  321. DEBUG_ECHOLNPGM("OCD finalized");
  322. }
  323. } break;
  324. case 2: {
  325. if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) { // skip all STALL_TH steps if L6474
  326. test_phase = 4;
  327. break;
  328. }
  329. if (status_composite & (sh.STATUS_AXIS_STEP_LOSS_A | sh.STATUS_AXIS_STEP_LOSS_B)) {
  330. // phase 2 with stall warning - time to go to next phase
  331. if (STALL_TH_val >= 127) {
  332. STALL_TH_val = 127; // limit to max
  333. //DEBUG_ECHOLNPGM("LOGIC E2A - STALL warning, STALL at max, quit");
  334. DEBUG_ECHOLNPGM("finished - STALL at maximum value but still have stall warning");
  335. test_phase = 4;
  336. }
  337. else {
  338. test_phase = 3; // normal exit to next phase (found failing value of STALL)
  339. STALL_TH_val++; // setup for first pass of phase 3
  340. //DEBUG_ECHOLNPGM("LOGIC E2B - INC - STALL warning, inc Stall, go to 3");
  341. DEBUG_ECHOLNPGM("inc Stall");
  342. }
  343. }
  344. else { // phase 2 without stall warning - decrement if can
  345. if (STALL_TH_val) {
  346. STALL_TH_val--; // try a lower value
  347. //DEBUG_ECHOLNPGM("LOGIC E2C - no STALL, dec STALL");
  348. DEBUG_ECHOLNPGM("dec STALL");
  349. }
  350. else {
  351. DEBUG_ECHOLNPGM("finished - STALL at lowest value but still do NOT have stall warning");
  352. test_phase = 4;
  353. //DEBUG_ECHOLNPGM("LOGIC E2D - no STALL, at lowest so quit");
  354. }
  355. }
  356. } break;
  357. case 3: {
  358. if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) { // skip all STALL_TH steps if L6474
  359. test_phase = 4;
  360. break;
  361. }
  362. if (status_composite & (sh.STATUS_AXIS_STEP_LOSS_A | sh.STATUS_AXIS_STEP_LOSS_B)) {
  363. // phase 3 with stall warning - increment if can
  364. if (STALL_TH_val >= 127) {
  365. STALL_TH_val = 127; // limit to max
  366. DEBUG_ECHOLNPGM("finished - STALL at maximum value but still have stall warning");
  367. test_phase = 4;
  368. //DEBUG_ECHOLNPGM("LOGIC E3A - STALL, at max so quit");
  369. }
  370. else {
  371. STALL_TH_val++; // still looking for passing value
  372. //DEBUG_ECHOLNPGM("LOGIC E3B - STALL, inc stall");
  373. DEBUG_ECHOLNPGM("inc stall");
  374. }
  375. }
  376. else { //phase 3 without stall warning but have OCD warning
  377. DEBUG_ECHOLNPGM("Hardware problem - OCD warning without STALL warning");
  378. test_phase = 4;
  379. //DEBUG_ECHOLNPGM("LOGIC E3C - not STALLED, hardware problem (quit)");
  380. }
  381. } break;
  382. }
  383. }
  384. else {
  385. switch (test_phase) {
  386. case 0: { // phase 0 without OCD warning - keep on decrementing if can
  387. if (OCD_TH_val) {
  388. OCD_TH_val--; // try lower value
  389. //DEBUG_ECHOLNPGM("LOGIC N0A - DEC OCD");
  390. DEBUG_ECHOLNPGM("DEC OCD");
  391. }
  392. else {
  393. test_phase = 2; // at lowest value without warning so skip phase 1
  394. //DEBUG_ECHOLNPGM("LOGIC N0B - OCD at lowest (go to phase 2)");
  395. DEBUG_ECHOLNPGM("OCD finalized");
  396. }
  397. } break;
  398. case 1: //DEBUG_ECHOLNPGM("LOGIC N1 (go directly to 2)"); // phase 1 without OCD warning - drop directly to phase 2
  399. DEBUG_ECHOLNPGM("OCD finalized");
  400. case 2: { // phase 2 without stall warning - keep on decrementing if can
  401. if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) { // skip all STALL_TH steps if L6474
  402. test_phase = 4;
  403. break;
  404. }
  405. if (STALL_TH_val) {
  406. STALL_TH_val--; // try a lower value (stay in phase 2)
  407. //DEBUG_ECHOLNPGM("LOGIC N2B - dec STALL");
  408. DEBUG_ECHOLNPGM("dec STALL");
  409. }
  410. else {
  411. DEBUG_ECHOLNPGM("finished - STALL at lowest value but still no stall warning");
  412. test_phase = 4;
  413. //DEBUG_ECHOLNPGM("LOGIC N2C - STALL at lowest (quit)");
  414. }
  415. } break;
  416. case 3: {
  417. if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) { // skip all STALL_TH steps if L6474
  418. test_phase = 4;
  419. break;
  420. }
  421. test_phase = 4;
  422. //DEBUG_ECHOLNPGM("LOGIC N3 - finished!");
  423. DEBUG_ECHOLNPGM("finished!");
  424. } break; // phase 3 without any warnings - desired exit
  425. } //
  426. } // end of status checks
  427. if (test_phase != 4) {
  428. for (j = 0; j < driver_count; j++) { // update threshold(s)
  429. L64xxManager.set_param(axis_index[j], L6470_OCD_TH, OCD_TH_val);
  430. if (sh.STATUS_AXIS_LAYOUT != L6474_STATUS_LAYOUT) L64xxManager.set_param(axis_index[j], L6470_STALL_TH, STALL_TH_val);
  431. if (L64xxManager.get_param(axis_index[j], L6470_OCD_TH) != OCD_TH_val) DEBUG_ECHOLNPGM("OCD mismatch");
  432. if ((L64xxManager.get_param(axis_index[j], L6470_STALL_TH) != STALL_TH_val) && (sh.STATUS_AXIS_LAYOUT != L6474_STATUS_LAYOUT)) DEBUG_ECHOLNPGM("STALL mismatch");
  433. }
  434. }
  435. } while (test_phase != 4);
  436. DEBUG_ECHOLNPGM(".");
  437. if (status_composite) {
  438. #if ENABLED(L6470_CHITCHAT)
  439. for (j = 0; j < driver_count; j++) {
  440. if (j) DEBUG_ECHOPGM("...");
  441. L64xxManager.error_status_decode(axis_status[j], axis_index[j],
  442. sh.STATUS_AXIS_TH_SD, sh.STATUS_AXIS_TH_WRN,
  443. sh.STATUS_AXIS_STEP_LOSS_A, sh.STATUS_AXIS_STEP_LOSS_B,
  444. sh.STATUS_AXIS_OCD, sh.STATUS_AXIS_LAYOUT);
  445. }
  446. DEBUG_ECHOLNPGM(".");
  447. #endif
  448. DEBUG_ECHOLNPGM("Completed with errors");
  449. }
  450. else
  451. DEBUG_ECHOLNPGM("Completed with no errors");
  452. DEBUG_ECHOLNPGM(".");
  453. L64xxManager.pause_monitor(false);
  454. }
  455. /**
  456. *
  457. * M918: increase speed until error or max feedrate achieved (as shown in configuration.h))
  458. *
  459. * J - select which driver(s) to monitor on multi-driver axis
  460. * 0 - (default) monitor all drivers on the axis or E0
  461. * 1 - monitor only X, Y, Z, E1
  462. * 2 - monitor only X2, Y2, Z2, E2
  463. * Xxxx, Yxxx, Zxxx, Exxx - axis to be monitored with displacement
  464. * xxx (1-255) is distance moved on either side of current position
  465. *
  466. * I - over current threshold
  467. * optional - will report current value from driver if not specified
  468. *
  469. * T - current (mA) setting for TVAL (0 - 4A in 31.25mA increments, rounds down) - L6474 only
  470. * optional - will report current value from driver if not specified
  471. *
  472. * K - value for KVAL_HOLD (0 - 255) (ignored for L6474)
  473. * optional - will report current value from driver if not specified
  474. *
  475. * M - value for microsteps (1 - 128) (optional)
  476. * optional - will report current value from driver if not specified
  477. *
  478. */
  479. void GcodeSuite::M918() {
  480. DEBUG_ECHOLNPGM("M918");
  481. L64xxManager.pause_monitor(true); // Keep monitor_driver() from stealing status
  482. char axis_mon[3][3] = { {" "}, {" "}, {" "} }; // list of Axes to be monitored
  483. L64XX_axis_t axis_index[3];
  484. uint16_t axis_status[3];
  485. uint8_t driver_count = 1;
  486. float position_max, position_min;
  487. float final_feedrate;
  488. uint8_t kval_hold;
  489. uint8_t OCD_TH_val = 0;
  490. uint8_t STALL_TH_val = 0;
  491. uint16_t over_current_threshold;
  492. constexpr uint8_t over_current_flag = true;
  493. const L64XX_Marlin::L64XX_shadow_t &sh = L64xxManager.shadow;
  494. uint8_t j; // general purpose counter
  495. if (L64xxManager.get_user_input(driver_count, axis_index, axis_mon, position_max, position_min, final_feedrate, kval_hold, over_current_flag, OCD_TH_val, STALL_TH_val, over_current_threshold))
  496. return; // quit if invalid user input
  497. L64xxManager.get_status(axis_index[0]); // populate shadow array
  498. uint8_t m_steps = parser.byteval('M');
  499. if (m_steps != 0) {
  500. LIMIT(m_steps, 1, sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT ? 16 : 128); // L6474
  501. uint8_t stepVal;
  502. for (stepVal = 0; stepVal < 8; stepVal++) { // convert to L64xx register value
  503. if (m_steps == 1) break;
  504. m_steps >>= 1;
  505. }
  506. if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT)
  507. stepVal |= 0x98; // NO SYNC
  508. else
  509. stepVal |= (!SYNC_EN) | SYNC_SEL_1 | stepVal;
  510. for (j = 0; j < driver_count; j++) {
  511. L64xxManager.set_param(axis_index[j], dSPIN_HARD_HIZ, 0); // can't write STEP register if stepper being powered
  512. // results in an extra NOOP being sent (data 00)
  513. L64xxManager.set_param(axis_index[j], L6470_STEP_MODE, stepVal); // set microsteps
  514. }
  515. }
  516. m_steps = L64xxManager.get_param(axis_index[0], L6470_STEP_MODE) & 0x07; // get microsteps
  517. DEBUG_ECHOLNPAIR("Microsteps = ", _BV(m_steps));
  518. DEBUG_ECHOLNPAIR("target (maximum) feedrate = ", final_feedrate);
  519. const float feedrate_inc = final_feedrate / 10, // Start at 1/10 of max & go up by 1/10 per step
  520. fr_limit = final_feedrate * 0.99f; // Rounding-safe comparison value
  521. float current_feedrate = 0;
  522. planner.synchronize(); // Wait for moves to complete
  523. for (j = 0; j < driver_count; j++)
  524. L64xxManager.get_status(axis_index[j]); // Clear error flags
  525. char temp_axis_string[2] = " ";
  526. temp_axis_string[0] = axis_mon[0][0]; // Need a sprintf format string
  527. //temp_axis_string[1] = '\n';
  528. char gcode_string[80];
  529. uint16_t status_composite = 0;
  530. DEBUG_ECHOLNPGM(".\n.\n."); // Make feedrate outputs easier to read
  531. do {
  532. current_feedrate += feedrate_inc;
  533. DEBUG_ECHOLNPAIR("...feedrate = ", current_feedrate);
  534. sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_min), uint16_t(current_feedrate));
  535. gcode.process_subcommands_now_P(gcode_string);
  536. sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_max), uint16_t(current_feedrate));
  537. gcode.process_subcommands_now_P(gcode_string);
  538. planner.synchronize();
  539. for (j = 0; j < driver_count; j++) {
  540. axis_status[j] = (~L64xxManager.get_status(axis_index[j])) & 0x0800; // Bits of interest are all active LOW
  541. status_composite |= axis_status[j];
  542. }
  543. if (status_composite) break; // Break on any error
  544. } while (current_feedrate < fr_limit);
  545. DEBUG_ECHOPGM("Completed with ");
  546. if (status_composite) {
  547. DEBUG_ECHOLNPGM("errors");
  548. #if ENABLED(L6470_CHITCHAT)
  549. for (j = 0; j < driver_count; j++) {
  550. if (j) DEBUG_ECHOPGM("...");
  551. L64xxManager.error_status_decode(axis_status[j], axis_index[j],
  552. sh.STATUS_AXIS_TH_SD, sh.STATUS_AXIS_TH_WRN,
  553. sh.STATUS_AXIS_STEP_LOSS_A, sh.STATUS_AXIS_STEP_LOSS_B,
  554. sh.STATUS_AXIS_OCD, sh.STATUS_AXIS_LAYOUT);
  555. }
  556. #endif
  557. }
  558. else
  559. DEBUG_ECHOLNPGM("no errors");
  560. L64xxManager.pause_monitor(false);
  561. }
  562. #endif // HAS_L64XX