My Marlin configs for Fabrikator Mini and CTC i3 Pro B
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

L6470_Marlin.cpp 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  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. * The monitor_driver routines are a close copy of the TMC code
  24. */
  25. #include "../../inc/MarlinConfig.h"
  26. #if HAS_DRIVER(L6470)
  27. #include "L6470_Marlin.h"
  28. L6470_Marlin L6470;
  29. #include "../../module/stepper/indirection.h"
  30. #include "../../module/planner.h"
  31. #include "../../gcode/gcode.h"
  32. #define DEBUG_OUT ENABLED(L6470_CHITCHAT)
  33. #include "../../core/debug_out.h"
  34. uint8_t L6470_Marlin::dir_commands[MAX_L6470]; // array to hold direction command for each driver
  35. char L6470_Marlin::index_to_axis[MAX_L6470][3] = { "X ", "Y ", "Z ", "X2", "Y2", "Z2", "Z3", "E0", "E1", "E2", "E3", "E4", "E5" };
  36. bool L6470_Marlin::index_to_dir[MAX_L6470] = {
  37. INVERT_X_DIR , // 0 X
  38. INVERT_Y_DIR , // 1 Y
  39. INVERT_Z_DIR , // 2 Z
  40. #if ENABLED(X_DUAL_STEPPER_DRIVERS)
  41. INVERT_X_DIR ^ INVERT_X2_VS_X_DIR , // 3 X2
  42. #else
  43. INVERT_X_DIR , // 3 X2
  44. #endif
  45. #if ENABLED(Y_DUAL_STEPPER_DRIVERS)
  46. INVERT_Y_DIR ^ INVERT_Y2_VS_Y_DIR , // 4 Y2
  47. #else
  48. INVERT_Y_DIR , // 4 Y2
  49. #endif
  50. INVERT_Z_DIR , // 5 Z2
  51. INVERT_Z_DIR , // 6 Z3
  52. INVERT_E0_DIR , // 7 E0
  53. INVERT_E1_DIR , // 8 E1
  54. INVERT_E2_DIR , // 9 E2
  55. INVERT_E3_DIR , //10 E3
  56. INVERT_E4_DIR , //11 E4
  57. INVERT_E5_DIR , //12 E5
  58. };
  59. uint8_t L6470_Marlin::axis_xref[MAX_L6470] = {
  60. AxisEnum(X_AXIS), // X
  61. AxisEnum(Y_AXIS), // Y
  62. AxisEnum(Z_AXIS), // Z
  63. AxisEnum(X_AXIS), // X2
  64. AxisEnum(Y_AXIS), // Y2
  65. AxisEnum(Z_AXIS), // Z2
  66. AxisEnum(Z_AXIS), // Z3
  67. AxisEnum(E_AXIS), // E0
  68. AxisEnum(E_AXIS), // E1
  69. AxisEnum(E_AXIS), // E2
  70. AxisEnum(E_AXIS), // E3
  71. AxisEnum(E_AXIS), // E4
  72. AxisEnum(E_AXIS) // E5
  73. };
  74. volatile bool L6470_Marlin::spi_abort = false;
  75. bool L6470_Marlin::spi_active = false;
  76. void L6470_Marlin::populate_chain_array() {
  77. #define _L6470_INIT_SPI(Q) do{ stepper##Q.set_chain_info(Q, Q##_CHAIN_POS); }while(0)
  78. #if AXIS_DRIVER_TYPE_X(L6470)
  79. _L6470_INIT_SPI(X);
  80. #endif
  81. #if AXIS_DRIVER_TYPE_X2(L6470)
  82. _L6470_INIT_SPI(X2);
  83. #endif
  84. #if AXIS_DRIVER_TYPE_Y(L6470)
  85. _L6470_INIT_SPI(Y);
  86. #endif
  87. #if AXIS_DRIVER_TYPE_Y2(L6470)
  88. _L6470_INIT_SPI(Y2);
  89. #endif
  90. #if AXIS_DRIVER_TYPE_Z(L6470)
  91. _L6470_INIT_SPI(Z);
  92. #endif
  93. #if AXIS_DRIVER_TYPE_Z2(L6470)
  94. _L6470_INIT_SPI(Z2);
  95. #endif
  96. #if AXIS_DRIVER_TYPE_Z3(L6470)
  97. _L6470_INIT_SPI(Z3);
  98. #endif
  99. #if AXIS_DRIVER_TYPE_E0(L6470)
  100. _L6470_INIT_SPI(E0);
  101. #endif
  102. #if AXIS_DRIVER_TYPE_E1(L6470)
  103. _L6470_INIT_SPI(E1);
  104. #endif
  105. #if AXIS_DRIVER_TYPE_E2(L6470)
  106. _L6470_INIT_SPI(E2);
  107. #endif
  108. #if AXIS_DRIVER_TYPE_E3(L6470)
  109. _L6470_INIT_SPI(E3);
  110. #endif
  111. #if AXIS_DRIVER_TYPE_E4(L6470)
  112. _L6470_INIT_SPI(E4);
  113. #endif
  114. #if AXIS_DRIVER_TYPE_E5(L6470)
  115. _L6470_INIT_SPI(E5);
  116. #endif
  117. }
  118. void L6470_Marlin::init() { // Set up SPI and then init chips
  119. #if PIN_EXISTS(L6470_RESET_CHAIN)
  120. OUT_WRITE(L6470_RESET_CHAIN_PIN, LOW); // hardware reset of drivers
  121. delay(1);
  122. OUT_WRITE(L6470_RESET_CHAIN_PIN, HIGH);
  123. delay(1); // need about 650uS for the chip to fully start up
  124. #endif
  125. populate_chain_array(); // Set up array to control where in the SPI transfer sequence a particular stepper's data goes
  126. L6470_spi_init(); // Set up L6470 soft SPI pins
  127. init_to_defaults(); // init the chips
  128. }
  129. uint16_t L6470_Marlin::get_status(const uint8_t axis) {
  130. #define GET_L6470_STATUS(Q) stepper##Q.getStatus()
  131. switch (axis) {
  132. #if AXIS_DRIVER_TYPE_X(L6470)
  133. case 0: return GET_L6470_STATUS(X);
  134. #endif
  135. #if AXIS_DRIVER_TYPE_Y(L6470)
  136. case 1: return GET_L6470_STATUS(Y);
  137. #endif
  138. #if AXIS_DRIVER_TYPE_Z(L6470)
  139. case 2: return GET_L6470_STATUS(Z);
  140. #endif
  141. #if AXIS_DRIVER_TYPE_X2(L6470)
  142. case 3: return GET_L6470_STATUS(X2);
  143. #endif
  144. #if AXIS_DRIVER_TYPE_Y2(L6470)
  145. case 4: return GET_L6470_STATUS(Y2);
  146. #endif
  147. #if AXIS_DRIVER_TYPE_Z2(L6470)
  148. case 5: return GET_L6470_STATUS(Z2);
  149. #endif
  150. #if AXIS_DRIVER_TYPE_Z3(L6470)
  151. case 6: return GET_L6470_STATUS(Z3);
  152. #endif
  153. #if AXIS_DRIVER_TYPE_E0(L6470)
  154. case 7: return GET_L6470_STATUS(E0);
  155. #endif
  156. #if AXIS_DRIVER_TYPE_E1(L6470)
  157. case 8: return GET_L6470_STATUS(E1);
  158. #endif
  159. #if AXIS_DRIVER_TYPE_E2(L6470)
  160. case 9: return GET_L6470_STATUS(E2);
  161. #endif
  162. #if AXIS_DRIVER_TYPE_E3(L6470)
  163. case 10: return GET_L6470_STATUS(E3);
  164. #endif
  165. #if AXIS_DRIVER_TYPE_E4(L6470)
  166. case 11: return GET_L6470_STATUS(E4);
  167. #endif
  168. #if AXIS_DRIVER_TYPE_E5(L6470)
  169. case 12: return GET_L6470_STATUS(E5);
  170. #endif
  171. }
  172. return 0; // Not needed but kills a compiler warning
  173. }
  174. uint32_t L6470_Marlin::get_param(uint8_t axis, uint8_t param) {
  175. #define GET_L6470_PARAM(Q) L6470_GETPARAM(param,Q)
  176. switch (axis) {
  177. #if AXIS_DRIVER_TYPE_X(L6470)
  178. case 0: return GET_L6470_PARAM(X);
  179. #endif
  180. #if AXIS_DRIVER_TYPE_Y(L6470)
  181. case 1: return GET_L6470_PARAM(Y);
  182. #endif
  183. #if AXIS_DRIVER_TYPE_Z(L6470)
  184. case 2: return GET_L6470_PARAM(Z);
  185. #endif
  186. #if AXIS_DRIVER_TYPE_X2(L6470)
  187. case 3: return GET_L6470_PARAM(X2);
  188. #endif
  189. #if AXIS_DRIVER_TYPE_Y2(L6470)
  190. case 4: return GET_L6470_PARAM(Y2);
  191. #endif
  192. #if AXIS_DRIVER_TYPE_Z2(L6470)
  193. case 5: return GET_L6470_PARAM(Z2);
  194. #endif
  195. #if AXIS_DRIVER_TYPE_Z3(L6470)
  196. case 6: return GET_L6470_PARAM(Z3);
  197. #endif
  198. #if AXIS_DRIVER_TYPE_E0(L6470)
  199. case 7: return GET_L6470_PARAM(E0);
  200. #endif
  201. #if AXIS_DRIVER_TYPE_E1(L6470)
  202. case 8: return GET_L6470_PARAM(E1);
  203. #endif
  204. #if AXIS_DRIVER_TYPE_E2(L6470)
  205. case 9: return GET_L6470_PARAM(E2);
  206. #endif
  207. #if AXIS_DRIVER_TYPE_E3(L6470)
  208. case 10: return GET_L6470_PARAM(E3);
  209. #endif
  210. #if AXIS_DRIVER_TYPE_E4(L6470)
  211. case 11: return GET_L6470_PARAM(E4);
  212. #endif
  213. #if AXIS_DRIVER_TYPE_E5(L6470)
  214. case 12: return GET_L6470_PARAM(E5);
  215. #endif
  216. }
  217. return 0 ; // not needed but kills a compiler warning
  218. }
  219. void L6470_Marlin::set_param(uint8_t axis, uint8_t param, uint32_t value) {
  220. #define SET_L6470_PARAM(Q) stepper##Q.SetParam(param, value)
  221. switch (axis) {
  222. #if AXIS_DRIVER_TYPE_X(L6470)
  223. case 0: SET_L6470_PARAM(X);
  224. #endif
  225. #if AXIS_DRIVER_TYPE_Y(L6470)
  226. case 1: SET_L6470_PARAM(Y);
  227. #endif
  228. #if AXIS_DRIVER_TYPE_Z(L6470)
  229. case 2: SET_L6470_PARAM(Z);
  230. #endif
  231. #if AXIS_DRIVER_TYPE_X2(L6470)
  232. case 3: SET_L6470_PARAM(X2);
  233. #endif
  234. #if AXIS_DRIVER_TYPE_Y2(L6470)
  235. case 4: SET_L6470_PARAM(Y2);
  236. #endif
  237. #if AXIS_DRIVER_TYPE_Z2(L6470)
  238. case 5: SET_L6470_PARAM(Z2);
  239. #endif
  240. #if AXIS_DRIVER_TYPE_Z3(L6470)
  241. case 6: SET_L6470_PARAM(Z3);
  242. #endif
  243. #if AXIS_DRIVER_TYPE_E0(L6470)
  244. case 7: SET_L6470_PARAM(E0);
  245. #endif
  246. #if AXIS_DRIVER_TYPE_E1(L6470)
  247. case 8: SET_L6470_PARAM(E1);
  248. #endif
  249. #if AXIS_DRIVER_TYPE_E2(L6470)
  250. case 9: SET_L6470_PARAM(E2);
  251. #endif
  252. #if AXIS_DRIVER_TYPE_E3(L6470)
  253. case 10: SET_L6470_PARAM(E3);
  254. #endif
  255. #if AXIS_DRIVER_TYPE_E4(L6470)
  256. case 11: SET_L6470_PARAM(E4);
  257. #endif
  258. #if AXIS_DRIVER_TYPE_E5(L6470)
  259. case 12: SET_L6470_PARAM(E5);
  260. #endif
  261. }
  262. }
  263. inline void echo_min_max(const char a, const float &min, const float &max) {
  264. DEBUG_CHAR(' '); DEBUG_CHAR(a);
  265. DEBUG_ECHOPAIR(" min = ", min);
  266. DEBUG_ECHOLNPAIR(" max = ", max);
  267. }
  268. inline void echo_oct_used(const float &oct, const bool stall) {
  269. DEBUG_ECHOPAIR("over_current_threshold used : ", oct);
  270. serialprintPGM(stall ? PSTR(" (Stall") : PSTR(" (OCD"));
  271. DEBUG_ECHOLNPGM(" threshold)");
  272. }
  273. inline void err_out_of_bounds() { DEBUG_ECHOLNPGM("ERROR - motion out of bounds"); }
  274. bool L6470_Marlin::get_user_input(uint8_t &driver_count, uint8_t axis_index[3], char axis_mon[3][3],
  275. float &position_max, float &position_min, float &final_feedrate, uint8_t &kval_hold,
  276. bool over_current_flag, uint8_t &OCD_TH_val, uint8_t &STALL_TH_val, uint16_t &over_current_threshold
  277. ) {
  278. // Return TRUE if the calling routine needs to abort/kill
  279. uint16_t displacement = 0; // " = 0" to eliminate compiler warning
  280. uint8_t j; // general purpose counter
  281. if (!all_axes_homed()) {
  282. DEBUG_ECHOLNPGM("ERROR - home all before running this command");
  283. //return true;
  284. }
  285. LOOP_XYZE(i) if (uint16_t _displacement = parser.intval(axis_codes[i])) {
  286. displacement = _displacement;
  287. uint8_t axis_offset = parser.byteval('J');
  288. axis_mon[0][0] = axis_codes[i]; // axis ASCII value (target character)
  289. if (axis_offset >= 2 || axis_mon[0][0] == 'E') // Single axis, E0, or E1
  290. axis_mon[0][1] = axis_offset + '0';
  291. else if (axis_offset == 0) { // one or more axes
  292. uint8_t driver_count_local = 0; // can't use "driver_count" directly as a subscript because it's passed by reference
  293. for (j = 0; j < MAX_L6470; j++) // see how many drivers on this axis
  294. if (axis_mon[0][0] == index_to_axis[j][0]) {
  295. axis_mon[driver_count_local][0] = axis_mon[0][0];
  296. axis_mon[driver_count_local][1] = index_to_axis[j][1];
  297. axis_mon[driver_count_local][2] = index_to_axis[j][2]; // append end of string
  298. axis_index[driver_count_local] = j; // set axis index
  299. driver_count_local++;
  300. }
  301. driver_count = driver_count_local;
  302. }
  303. break; // only take first axis found
  304. }
  305. //
  306. // Position calcs & checks
  307. //
  308. const xyze_pos_t center = {
  309. LOGICAL_X_POSITION(current_position.x),
  310. LOGICAL_Y_POSITION(current_position.y),
  311. LOGICAL_Z_POSITION(current_position.z),
  312. current_position.e
  313. };
  314. switch (axis_mon[0][0]) {
  315. default: position_max = position_min = 0; break;
  316. case 'X': {
  317. position_min = center.x - displacement;
  318. position_max = center.x + displacement;
  319. echo_min_max('X', position_min, position_max);
  320. if (false
  321. #ifdef X_MIN_POS
  322. || position_min < (X_MIN_POS)
  323. #endif
  324. #ifdef X_MAX_POS
  325. || position_max > (X_MAX_POS)
  326. #endif
  327. ) {
  328. err_out_of_bounds();
  329. return true;
  330. }
  331. } break;
  332. case 'Y': {
  333. position_min = center.y - displacement;
  334. position_max = center.y + displacement;
  335. echo_min_max('Y', position_min, position_max);
  336. if (false
  337. #ifdef Y_MIN_POS
  338. || position_min < (Y_MIN_POS)
  339. #endif
  340. #ifdef Y_MAX_POS
  341. || position_max > (Y_MAX_POS)
  342. #endif
  343. ) {
  344. err_out_of_bounds();
  345. return true;
  346. }
  347. } break;
  348. case 'Z': {
  349. position_min = center.z - displacement;
  350. position_max = center.z + displacement;
  351. echo_min_max('Z', position_min, position_max);
  352. if (false
  353. #ifdef Z_MIN_POS
  354. || position_min < (Z_MIN_POS)
  355. #endif
  356. #ifdef Z_MAX_POS
  357. || position_max > (Z_MAX_POS)
  358. #endif
  359. ) {
  360. err_out_of_bounds();
  361. return true;
  362. }
  363. } break;
  364. case 'E': {
  365. position_min = center.e - displacement;
  366. position_max = center.e + displacement;
  367. echo_min_max('E', position_min, position_max);
  368. } break;
  369. }
  370. //
  371. // Work on the drivers
  372. //
  373. for (uint8_t k = 0; k < driver_count; k++) {
  374. bool not_found = true;
  375. for (j = 1; j <= L6470::chain[0]; j++) {
  376. const char * const ind_axis = index_to_axis[L6470::chain[j]];
  377. if (ind_axis[0] == axis_mon[k][0] && ind_axis[1] == axis_mon[k][1]) { // See if a L6470 driver
  378. not_found = false;
  379. break;
  380. }
  381. }
  382. if (not_found) {
  383. driver_count = k;
  384. axis_mon[k][0] = ' '; // mark this entry invalid
  385. break;
  386. }
  387. }
  388. if (driver_count == 0) {
  389. DEBUG_ECHOLNPGM("ERROR - not a L6470 axis");
  390. return true;
  391. }
  392. DEBUG_ECHOPGM("Monitoring:");
  393. for (j = 0; j < driver_count; j++) DEBUG_ECHOPAIR(" ", axis_mon[j]);
  394. L6470_EOL();
  395. // now have a list of driver(s) to monitor
  396. //
  397. // kVAL_HOLD checks & settings
  398. //
  399. kval_hold = parser.byteval('K');
  400. if (kval_hold) {
  401. DEBUG_ECHOLNPAIR("kval_hold = ", kval_hold);
  402. for (j = 0; j < driver_count; j++)
  403. set_param(axis_index[j], L6470_KVAL_HOLD, kval_hold);
  404. }
  405. else {
  406. // only print the KVAL_HOLD from one of the drivers
  407. kval_hold = get_param(axis_index[0], L6470_KVAL_HOLD);
  408. DEBUG_ECHOLNPAIR("KVAL_HOLD = ", kval_hold);
  409. }
  410. //
  411. // Overcurrent checks & settings
  412. //
  413. if (over_current_flag) {
  414. uint8_t OCD_TH_val_local = 0, // compiler thinks OCD_TH_val is unused if use it directly
  415. STALL_TH_val_local = 0; // just in case ...
  416. over_current_threshold = parser.intval('I');
  417. if (over_current_threshold) {
  418. OCD_TH_val_local = over_current_threshold/375;
  419. LIMIT(OCD_TH_val_local, 0, 15);
  420. STALL_TH_val_local = over_current_threshold/31.25;
  421. LIMIT(STALL_TH_val_local, 0, 127);
  422. uint16_t OCD_TH_actual = (OCD_TH_val_local + 1) * 375,
  423. STALL_TH_actual = (STALL_TH_val_local + 1) * 31.25;
  424. if (OCD_TH_actual < STALL_TH_actual) {
  425. OCD_TH_val_local++;
  426. OCD_TH_actual = (OCD_TH_val_local + 1) * 375;
  427. }
  428. DEBUG_ECHOLNPAIR("over_current_threshold specified: ", over_current_threshold);
  429. echo_oct_used(STALL_TH_actual, true);
  430. echo_oct_used(OCD_TH_actual, false);
  431. #define SET_OVER_CURRENT(Q) do { stepper##Q.SetParam(L6470_STALL_TH, STALL_TH_val_local); stepper##Q.SetParam(L6470_OCD_TH, OCD_TH_val_local);} while (0)
  432. for (j = 0; j < driver_count; j++) {
  433. set_param(axis_index[j], L6470_STALL_TH, STALL_TH_val_local);
  434. set_param(axis_index[j], L6470_OCD_TH, OCD_TH_val_local);
  435. }
  436. }
  437. else {
  438. // only get & print the OVER_CURRENT values from one of the drivers
  439. STALL_TH_val_local = get_param(axis_index[0], L6470_STALL_TH);
  440. OCD_TH_val_local = get_param(axis_index[0], L6470_OCD_TH);
  441. echo_oct_used((STALL_TH_val_local + 1) * 31.25, true);
  442. echo_oct_used((OCD_TH_val_local + 1) * 375, false);
  443. } // over_current_threshold
  444. for (j = 0; j < driver_count; j++) { // set all drivers on axis the same
  445. set_param(axis_index[j], L6470_STALL_TH, STALL_TH_val_local);
  446. set_param(axis_index[j], L6470_OCD_TH, OCD_TH_val_local);
  447. }
  448. OCD_TH_val = OCD_TH_val_local; // force compiler to update the main routine's copy
  449. STALL_TH_val = STALL_TH_val_local; // force compiler to update the main routine's copy
  450. } // end of overcurrent
  451. //
  452. // Feedrate
  453. //
  454. final_feedrate = parser.floatval('F');
  455. if (final_feedrate == 0) {
  456. static constexpr float default_max_feedrate[] = DEFAULT_MAX_FEEDRATE;
  457. const uint8_t num_feedrates = COUNT(default_max_feedrate);
  458. for (j = 0; j < num_feedrates; j++) {
  459. if (axis_codes[j] == axis_mon[0][0]) {
  460. final_feedrate = default_max_feedrate[j];
  461. break;
  462. }
  463. }
  464. if (j == 3 && num_feedrates > 4) { // have more than one extruder feedrate
  465. uint8_t extruder_num = axis_mon[0][1] - '0';
  466. if (j <= num_feedrates - extruder_num) // have a feedrate specifically for this extruder
  467. final_feedrate = default_max_feedrate[j + extruder_num];
  468. else
  469. final_feedrate = default_max_feedrate[3]; // use E0 feedrate for this extruder
  470. }
  471. final_feedrate *= 60; // convert to mm/minute
  472. } // end of feedrate
  473. return false; // FALSE indicates no user input problems
  474. }
  475. #if ENABLED(L6470_CHITCHAT)
  476. inline void echo_yes_no(const bool yes) { serialprintPGM(yes ? PSTR("YES") : PSTR("NO ")); }
  477. #endif
  478. void L6470_Marlin::say_axis(const uint8_t axis, const bool label/*=true*/) {
  479. if (label) SERIAL_ECHOPGM("AXIS:");
  480. SERIAL_CHAR(' ', index_to_axis[axis][0], index_to_axis[axis][1], ' ');
  481. }
  482. void L6470_Marlin::error_status_decode(const uint16_t status, const uint8_t axis) { // assumes status bits have been inverted
  483. #if ENABLED(L6470_CHITCHAT)
  484. char temp_buf[10];
  485. say_axis(axis);
  486. sprintf_P(temp_buf, PSTR(" %4x "), status);
  487. DEBUG_ECHO(temp_buf);
  488. print_bin(status);
  489. DEBUG_ECHOPGM(" THERMAL: ");
  490. serialprintPGM((status & STATUS_TH_SD) ? PSTR("SHUTDOWN") : (status & STATUS_TH_WRN) ? PSTR("WARNING ") : PSTR("OK "));
  491. DEBUG_ECHOPGM(" OVERCURRENT: ");
  492. echo_yes_no(status & STATUS_OCD);
  493. DEBUG_ECHOPGM(" STALL: ");
  494. echo_yes_no(status & (STATUS_STEP_LOSS_A | STATUS_STEP_LOSS_B));
  495. L6470_EOL();
  496. #else
  497. UNUSED(status); UNUSED(axis);
  498. #endif
  499. }
  500. //////////////////////////////////////////////////////////////////////////////////////////////////
  501. ////
  502. //// MONITOR_L6470_DRIVER_STATUS routines
  503. ////
  504. //////////////////////////////////////////////////////////////////////////////////////////////////
  505. #if ENABLED(MONITOR_L6470_DRIVER_STATUS)
  506. struct L6470_driver_data {
  507. uint8_t driver_index;
  508. uint32_t driver_status;
  509. bool is_otw;
  510. uint8_t otw_counter;
  511. bool is_ot;
  512. bool is_hi_Z;
  513. uint8_t com_counter;
  514. };
  515. L6470_driver_data driver_L6470_data[] = {
  516. #if AXIS_DRIVER_TYPE_X(L6470)
  517. { 0, 0, 0, 0, 0, 0, 0 },
  518. #endif
  519. #if AXIS_DRIVER_TYPE_Y(L6470)
  520. { 1, 0, 0, 0, 0, 0, 0 },
  521. #endif
  522. #if AXIS_DRIVER_TYPE_Z(L6470)
  523. { 2, 0, 0, 0, 0, 0, 0 },
  524. #endif
  525. #if AXIS_DRIVER_TYPE_X2(L6470)
  526. { 3, 0, 0, 0, 0, 0, 0 },
  527. #endif
  528. #if AXIS_DRIVER_TYPE_Y2(L6470)
  529. { 4, 0, 0, 0, 0, 0, 0 },
  530. #endif
  531. #if AXIS_DRIVER_TYPE_Z2(L6470)
  532. { 5, 0, 0, 0, 0, 0, 0 },
  533. #endif
  534. #if AXIS_DRIVER_TYPE_Z3(L6470)
  535. { 6, 0, 0, 0, 0, 0, 0 },
  536. #endif
  537. #if AXIS_DRIVER_TYPE_E0(L6470)
  538. { 7, 0, 0, 0, 0, 0, 0 },
  539. #endif
  540. #if AXIS_DRIVER_TYPE_E1(L6470)
  541. { 8, 0, 0, 0, 0, 0, 0 },
  542. #endif
  543. #if AXIS_DRIVER_TYPE_E2(L6470)
  544. { 9, 0, 0, 0, 0, 0, 0 },
  545. #endif
  546. #if AXIS_DRIVER_TYPE_E3(L6470)
  547. { 10, 0, 0, 0, 0, 0, 0 },
  548. #endif
  549. #if AXIS_DRIVER_TYPE_E4(L6470)
  550. { 11, 0, 0, 0, 0, 0, 0 },
  551. #endif
  552. #if AXIS_DRIVER_TYPE_E5(L6470)
  553. { 12, 0, 0, 0, 0, 0, 0 }
  554. #endif
  555. };
  556. inline void append_stepper_err(char * &p, const uint8_t stepper_index, const char * const err=nullptr) {
  557. p += sprintf_P(p, PSTR("Stepper %c%c "), char(index_to_axis[stepper_index][0]), char(index_to_axis[stepper_index][1]));
  558. if (err) p += sprintf_P(p, err);
  559. }
  560. void L6470_monitor_update(uint8_t stepper_index, uint16_t status) {
  561. if (spi_abort) return; // don't do anything if set_directions() has occurred
  562. uint8_t kval_hold;
  563. char temp_buf[120];
  564. char* p = &temp_buf[0];
  565. uint8_t j;
  566. for (j = 0; j < L6470::chain[0]; j++) // find the table for this stepper
  567. if (driver_L6470_data[j].driver_index == stepper_index) break;
  568. driver_L6470_data[j].driver_status = status;
  569. uint16_t _status = ~status; // all error bits are active low
  570. if (status == 0 || status == 0xFFFF) { // com problem
  571. if (driver_L6470_data[j].com_counter == 0) { // warn user when it first happens
  572. driver_L6470_data[j].com_counter++;
  573. append_stepper_err(p, stepper_index, PSTR(" - communications lost\n"));
  574. DEBUG_ECHO(temp_buf);
  575. }
  576. else {
  577. driver_L6470_data[j].com_counter++;
  578. if (driver_L6470_data[j].com_counter > 240) { // remind of com problem about every 2 minutes
  579. driver_L6470_data[j].com_counter = 1;
  580. append_stepper_err(p, stepper_index, PSTR(" - still no communications\n"));
  581. DEBUG_ECHO(temp_buf);
  582. }
  583. }
  584. }
  585. else {
  586. if (driver_L6470_data[j].com_counter) { // comms re-established
  587. driver_L6470_data[j].com_counter = 0;
  588. append_stepper_err(p, stepper_index, PSTR(" - communications re-established\n.. setting all drivers to default values\n"));
  589. DEBUG_ECHO(temp_buf);
  590. init_to_defaults();
  591. }
  592. else {
  593. // no com problems - do the usual checks
  594. if (_status & L6470_ERROR_MASK) {
  595. append_stepper_err(p, stepper_index);
  596. if (status & STATUS_HIZ) { // the driver has shut down HiZ is active high
  597. driver_L6470_data[j].is_hi_Z = true;
  598. p += sprintf_P(p, PSTR("%cIS SHUT DOWN"), ' ');
  599. // if (_status & STATUS_TH_SD) { // strange - TH_SD never seems to go active, must be implied by the HiZ and TH_WRN
  600. if (_status & STATUS_TH_WRN) { // over current shutdown
  601. p += sprintf_P(p, PSTR("%cdue to over temperature"), ' ');
  602. driver_L6470_data[j].is_ot = true;
  603. kval_hold = get_param(stepper_index, L6470_KVAL_HOLD) - 2 * KVAL_HOLD_STEP_DOWN;
  604. set_param(stepper_index, L6470_KVAL_HOLD, kval_hold); // reduce KVAL_HOLD
  605. p += sprintf_P(p, PSTR(" - KVAL_HOLD reduced by %d to %d"), 2 * KVAL_HOLD_STEP_DOWN, kval_hold); // let user know
  606. }
  607. else
  608. driver_L6470_data[j].is_ot = false;
  609. }
  610. else {
  611. driver_L6470_data[j].is_hi_Z = false;
  612. if (_status & STATUS_TH_WRN) { // have an over temperature warning
  613. driver_L6470_data[j].is_otw = true;
  614. driver_L6470_data[j].otw_counter++;
  615. kval_hold = get_param(stepper_index, L6470_KVAL_HOLD);
  616. if (driver_L6470_data[j].otw_counter > 4) { // otw present for 2 - 2.5 seconds, reduce KVAL_HOLD
  617. kval_hold -= KVAL_HOLD_STEP_DOWN;
  618. set_param(stepper_index, L6470_KVAL_HOLD, kval_hold); // reduce KVAL_HOLD
  619. p += sprintf_P(p, PSTR(" - KVAL_HOLD reduced by %d to %d"), KVAL_HOLD_STEP_DOWN, kval_hold); // let user know
  620. driver_L6470_data[j].otw_counter = 0;
  621. driver_L6470_data[j].is_otw = true;
  622. }
  623. else if (driver_L6470_data[j].otw_counter)
  624. p += sprintf_P(p, PSTR("%c- thermal warning"), ' '); // warn user
  625. }
  626. }
  627. #ifdef L6470_STOP_ON_ERROR
  628. if (_status & (STATUS_UVLO | STATUS_TH_WRN | STATUS_TH_SD))
  629. kill(temp_buf);
  630. #endif
  631. #if ENABLED(L6470_CHITCHAT)
  632. if (_status & STATUS_OCD)
  633. p += sprintf_P(p, PSTR("%c over current"), ' ');
  634. if (_status & (STATUS_STEP_LOSS_A | STATUS_STEP_LOSS_B))
  635. p += sprintf_P(p, PSTR("%c stall"), ' ');
  636. if (_status & STATUS_UVLO)
  637. p += sprintf_P(p, PSTR("%c under voltage lock out"), ' ');
  638. p += sprintf_P(p, PSTR("%c\n"), ' ');
  639. #endif
  640. DEBUG_ECHOLN(temp_buf); // print the error message
  641. }
  642. else {
  643. driver_L6470_data[j].is_ot = false;
  644. driver_L6470_data[j].otw_counter = 0; //clear out warning indicators
  645. driver_L6470_data[j].is_otw = false;
  646. } // end usual checks
  647. } // comms established but have errors
  648. } // comms re-established
  649. } // end L6470_monitor_update()
  650. #define MONITOR_L6470_DRIVE(Q) L6470_monitor_update(Q, stepper##Q.getStatus())
  651. void L6470_Marlin::monitor_driver() {
  652. static millis_t next_cOT = 0;
  653. if (ELAPSED(millis(), next_cOT)) {
  654. next_cOT = millis() + 500;
  655. spi_active = true; // let set_directions() know we're in the middle of a series of SPI transfers
  656. #if AXIS_DRIVER_TYPE_X(L6470)
  657. MONITOR_L6470_DRIVE(X);
  658. #endif
  659. #if AXIS_DRIVER_TYPE_Y(L6470)
  660. MONITOR_L6470_DRIVE(Y);
  661. #endif
  662. #if AXIS_DRIVER_TYPE_Z(L6470)
  663. MONITOR_L6470_DRIVE(Z);
  664. #endif
  665. #if AXIS_DRIVER_TYPE_X2(L6470)
  666. MONITOR_L6470_DRIVE(X2);
  667. #endif
  668. #if AXIS_DRIVER_TYPE_Y2(L6470)
  669. MONITOR_L6470_DRIVE(Y2);
  670. #endif
  671. #if AXIS_DRIVER_TYPE_Z2(L6470)
  672. MONITOR_L6470_DRIVE(Z2);
  673. #endif
  674. #if AXIS_DRIVER_TYPE_Z3(L6470)
  675. MONITOR_L6470_DRIVE(Z3);
  676. #endif
  677. #if AXIS_DRIVER_TYPE_E0(L6470)
  678. MONITOR_L6470_DRIVE(E0);
  679. #endif
  680. #if AXIS_DRIVER_TYPE_E1(L6470)
  681. MONITOR_L6470_DRIVE(E1);
  682. #endif
  683. #if AXIS_DRIVER_TYPE_E2(L6470)
  684. MONITOR_L6470_DRIVE(E2);
  685. #endif
  686. #if AXIS_DRIVER_TYPE_E3(L6470)
  687. MONITOR_L6470_DRIVE(E3);
  688. #endif
  689. #if AXIS_DRIVER_TYPE_E4(L6470)
  690. MONITOR_L6470_DRIVE(E4);
  691. #endif
  692. #if AXIS_DRIVER_TYPE_E5(L6470)
  693. MONITOR_L6470_DRIVE(E5);
  694. #endif
  695. #if ENABLED(L6470_DEBUG)
  696. if (report_L6470_status) L6470_EOL();
  697. #endif
  698. spi_active = false; // done with all SPI transfers - clear handshake flags
  699. spi_abort = false;
  700. }
  701. }
  702. #endif // MONITOR_L6470_DRIVER_STATUS
  703. #endif // HAS_DRIVER(L6470)