My Marlin configs for Fabrikator Mini and CTC i3 Pro B
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

tmc_util.cpp 31KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029
  1. /**
  2. * Marlin 3D Printer Firmware
  3. * Copyright (C) 2016 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. #include "../inc/MarlinConfig.h"
  23. #if HAS_TRINAMIC
  24. #include "tmc_util.h"
  25. #include "../Marlin.h"
  26. #include "../module/stepper_indirection.h"
  27. #include "../module/printcounter.h"
  28. #include "../libs/duration_t.h"
  29. #include "../gcode/gcode.h"
  30. #if ENABLED(TMC_DEBUG)
  31. #include "../module/planner.h"
  32. #include "../libs/hex_print_routines.h"
  33. #if ENABLED(MONITOR_DRIVER_STATUS)
  34. static bool report_tmc_status; // = false;
  35. #endif
  36. #endif
  37. #if HAS_LCD_MENU
  38. #include "../module/stepper.h"
  39. #endif
  40. /**
  41. * Check for over temperature or short to ground error flags.
  42. * Report and log warning of overtemperature condition.
  43. * Reduce driver current in a persistent otpw condition.
  44. * Keep track of otpw counter so we don't reduce current on a single instance,
  45. * and so we don't repeatedly report warning before the condition is cleared.
  46. */
  47. #if ENABLED(MONITOR_DRIVER_STATUS)
  48. struct TMC_driver_data {
  49. uint32_t drv_status;
  50. bool is_otpw,
  51. is_ot,
  52. is_s2ga,
  53. is_s2gb,
  54. is_error;
  55. };
  56. #if HAS_DRIVER(TMC2130)
  57. #if ENABLED(TMC_DEBUG)
  58. static uint32_t get_pwm_scale(TMC2130Stepper &st) { return st.PWM_SCALE(); }
  59. static uint8_t get_status_response(TMC2130Stepper &st, uint32_t) { return st.status_response & 0xF; }
  60. #endif
  61. static TMC_driver_data get_driver_data(TMC2130Stepper &st) {
  62. constexpr uint32_t OTPW_bm = 0x4000000UL;
  63. constexpr uint8_t OTPW_bp = 26;
  64. constexpr uint32_t OT_bm = 0x2000000UL;
  65. constexpr uint8_t OT_bp = 25;
  66. constexpr uint8_t S2GA_bp = 27;
  67. constexpr uint8_t S2GB_bp = 28;
  68. TMC_driver_data data;
  69. data.drv_status = st.DRV_STATUS();
  70. data.is_otpw = (data.drv_status & OTPW_bm) >> OTPW_bp;
  71. data.is_ot = (data.drv_status & OT_bm) >> OT_bp;
  72. data.is_s2ga = (data.drv_status >> S2GA_bp) & 0b1;
  73. data.is_s2gb = (data.drv_status >> S2GB_bp) & 0b1;
  74. return data;
  75. }
  76. #endif
  77. #if HAS_DRIVER(TMC2208)
  78. #if ENABLED(TMC_DEBUG)
  79. static uint32_t get_pwm_scale(TMC2208Stepper &st) { return st.pwm_scale_sum(); }
  80. static uint8_t get_status_response(TMC2208Stepper &st, uint32_t drv_status) {
  81. uint8_t gstat = st.GSTAT();
  82. uint8_t response = 0;
  83. response |= (drv_status >> (31 - 3)) & 0b1000;
  84. response |= gstat & 0b11;
  85. return response;
  86. }
  87. #endif
  88. static TMC_driver_data get_driver_data(TMC2208Stepper &st) {
  89. constexpr uint32_t OTPW_bm = 0b1ul;
  90. constexpr uint8_t OTPW_bp = 0;
  91. constexpr uint32_t OT_bm = 0b10ul;
  92. constexpr uint8_t OT_bp = 1;
  93. constexpr uint8_t S2GA_bp = 2;
  94. constexpr uint8_t S2GB_bp = 3;
  95. TMC_driver_data data;
  96. data.drv_status = st.DRV_STATUS();
  97. data.is_otpw = (data.drv_status & OTPW_bm) >> OTPW_bp;
  98. data.is_ot = (data.drv_status & OT_bm) >> OT_bp;
  99. data.is_s2ga = (data.drv_status >> S2GA_bp) & 0b1;
  100. data.is_s2gb = (data.drv_status >> S2GB_bp) & 0b1;
  101. return data;
  102. }
  103. #endif
  104. #if HAS_DRIVER(TMC2660)
  105. #if ENABLED(TMC_DEBUG)
  106. static uint32_t get_pwm_scale(TMC2660Stepper) { return 0; }
  107. static uint8_t get_status_response(TMC2660Stepper, uint32_t drv_status) {
  108. return drv_status & 0xFF;
  109. }
  110. #endif
  111. static TMC_driver_data get_driver_data(TMC2660Stepper &st) {
  112. constexpr uint32_t OTPW_bm = 0x4UL;
  113. constexpr uint8_t OTPW_bp = 2;
  114. constexpr uint32_t OT_bm = 0x2UL;
  115. constexpr uint8_t OT_bp = 1;
  116. TMC_driver_data data;
  117. data.drv_status = st.DRVSTATUS();
  118. data.is_otpw = (data.drv_status & OTPW_bm) >> OTPW_bp;
  119. data.is_ot = (data.drv_status & OT_bm) >> OT_bp;
  120. return data;
  121. }
  122. #endif
  123. #if ENABLED(STOP_ON_ERROR)
  124. void report_driver_error(const TMC_driver_data &data) {
  125. SERIAL_ECHOPGM(" driver error detected: 0x");
  126. SERIAL_PRINTLN(data.drv_status, HEX);
  127. if (data.is_ot) SERIAL_ECHOLNPGM("overtemperature");
  128. if (data.is_s2ga) SERIAL_ECHOLNPGM("short to ground (coil A)");
  129. if (data.is_s2gb) SERIAL_ECHOLNPGM("short to ground (coil B)");
  130. #if ENABLED(TMC_DEBUG)
  131. tmc_report_all(true, true, true, true);
  132. #endif
  133. kill(PSTR("Driver error"));
  134. }
  135. #endif
  136. template<typename TMC>
  137. void report_driver_otpw(TMC &st) {
  138. char timestamp[14];
  139. duration_t elapsed = print_job_timer.duration();
  140. const bool has_days = (elapsed.value > 60*60*24L);
  141. (void)elapsed.toDigital(timestamp, has_days);
  142. SERIAL_EOL();
  143. SERIAL_ECHO(timestamp);
  144. SERIAL_ECHOPGM(": ");
  145. st.printLabel();
  146. SERIAL_ECHOPGM(" driver overtemperature warning! (");
  147. SERIAL_ECHO(st.getMilliamps());
  148. SERIAL_ECHOLNPGM("mA)");
  149. }
  150. template<typename TMC>
  151. void report_polled_driver_data(TMC &st, const TMC_driver_data &data) {
  152. const uint32_t pwm_scale = get_pwm_scale(st);
  153. st.printLabel();
  154. SERIAL_ECHOPAIR(":", pwm_scale);
  155. SERIAL_ECHOPGM(" |0b"); SERIAL_PRINT(get_status_response(st, data.drv_status), BIN);
  156. SERIAL_ECHOPGM("| ");
  157. if (st.error_count) SERIAL_CHAR('E');
  158. else if (data.is_ot) SERIAL_CHAR('O');
  159. else if (data.is_otpw) SERIAL_CHAR('W');
  160. else if (st.otpw_count > 0) SERIAL_PRINT(st.otpw_count, DEC);
  161. else if (st.flag_otpw) SERIAL_CHAR('F');
  162. SERIAL_CHAR('\t');
  163. }
  164. template<typename TMC>
  165. void monitor_tmc_driver(TMC &st) {
  166. TMC_driver_data data = get_driver_data(st);
  167. if ((data.drv_status == 0xFFFFFFFF) || (data.drv_status == 0x0)) return;
  168. if (data.is_ot /* | data.s2ga | data.s2gb*/) st.error_count++;
  169. else if (st.error_count > 0) st.error_count--;
  170. #if ENABLED(STOP_ON_ERROR)
  171. if (st.error_count >= 10) {
  172. SERIAL_EOL();
  173. st.printLabel();
  174. report_driver_error(data);
  175. }
  176. #endif
  177. // Report if a warning was triggered
  178. if (data.is_otpw && st.otpw_count == 0) {
  179. report_driver_otpw(st);
  180. }
  181. #if CURRENT_STEP_DOWN > 0
  182. // Decrease current if is_otpw is true and driver is enabled and there's been more than 4 warnings
  183. if (data.is_otpw && st.otpw_count > 4) {
  184. uint16_t I_rms = st.getMilliamps();
  185. if (st.isEnabled() && I_rms > 100) {
  186. st.rms_current(I_rms - (CURRENT_STEP_DOWN));
  187. #if ENABLED(REPORT_CURRENT_CHANGE)
  188. st.printLabel();
  189. SERIAL_ECHOLNPAIR(" current decreased to ", st.getMilliamps());
  190. #endif
  191. }
  192. }
  193. #endif
  194. if (data.is_otpw) {
  195. st.otpw_count++;
  196. st.flag_otpw = true;
  197. }
  198. else if (st.otpw_count > 0) st.otpw_count = 0;
  199. #if ENABLED(TMC_DEBUG)
  200. if (report_tmc_status) {
  201. report_polled_driver_data(st, data);
  202. }
  203. #endif
  204. }
  205. #define HAS_HW_COMMS(ST) AXIS_DRIVER_TYPE(ST, TMC2130) || AXIS_DRIVER_TYPE(ST, TMC2660) || (AXIS_DRIVER_TYPE(ST, TMC2208) && defined(ST##_HARDWARE_SERIAL))
  206. void monitor_tmc_driver() {
  207. static millis_t next_poll = 0;
  208. const millis_t ms = millis();
  209. if (ELAPSED(ms, next_poll)) {
  210. next_poll = ms + 500;
  211. #if HAS_HW_COMMS(X)
  212. monitor_tmc_driver(stepperX);
  213. #endif
  214. #if HAS_HW_COMMS(Y)
  215. monitor_tmc_driver(stepperY);
  216. #endif
  217. #if HAS_HW_COMMS(Z)
  218. monitor_tmc_driver(stepperZ);
  219. #endif
  220. #if HAS_HW_COMMS(X2)
  221. monitor_tmc_driver(stepperX2);
  222. #endif
  223. #if HAS_HW_COMMS(Y2)
  224. monitor_tmc_driver(stepperY2);
  225. #endif
  226. #if HAS_HW_COMMS(Z2)
  227. monitor_tmc_driver(stepperZ2);
  228. #endif
  229. #if HAS_HW_COMMS(Z3)
  230. monitor_tmc_driver(stepperZ3);
  231. #endif
  232. #if HAS_HW_COMMS(E0)
  233. monitor_tmc_driver(stepperE0);
  234. #endif
  235. #if HAS_HW_COMMS(E1)
  236. monitor_tmc_driver(stepperE1);
  237. #endif
  238. #if HAS_HW_COMMS(E2)
  239. monitor_tmc_driver(stepperE2);
  240. #endif
  241. #if HAS_HW_COMMS(E3)
  242. monitor_tmc_driver(stepperE3);
  243. #endif
  244. #if HAS_HW_COMMS(E4)
  245. monitor_tmc_driver(stepperE4);
  246. #endif
  247. #if HAS_HW_COMMS(E5)
  248. monitor_tmc_driver(stepperE5);
  249. #endif
  250. #if ENABLED(TMC_DEBUG)
  251. if (report_tmc_status) SERIAL_EOL();
  252. #endif
  253. }
  254. }
  255. #endif // MONITOR_DRIVER_STATUS
  256. #if ENABLED(TMC_DEBUG)
  257. /**
  258. * M122 S[1,0] Enable periodic status reports
  259. */
  260. #if ENABLED(MONITOR_DRIVER_STATUS)
  261. void tmc_set_report_status(const bool status) {
  262. if ((report_tmc_status = status))
  263. SERIAL_ECHOLNPGM("axis:pwm_scale |status_response|");
  264. }
  265. #endif
  266. enum TMC_debug_enum : char {
  267. TMC_CODES,
  268. TMC_ENABLED,
  269. TMC_CURRENT,
  270. TMC_RMS_CURRENT,
  271. TMC_MAX_CURRENT,
  272. TMC_IRUN,
  273. TMC_IHOLD,
  274. TMC_CS_ACTUAL,
  275. TMC_PWM_SCALE,
  276. TMC_VSENSE,
  277. TMC_STEALTHCHOP,
  278. TMC_MICROSTEPS,
  279. TMC_TSTEP,
  280. TMC_TPWMTHRS,
  281. TMC_TPWMTHRS_MMS,
  282. TMC_OTPW,
  283. TMC_OTPW_TRIGGERED,
  284. TMC_TOFF,
  285. TMC_TBL,
  286. TMC_HEND,
  287. TMC_HSTRT,
  288. TMC_SGT
  289. };
  290. enum TMC_drv_status_enum : char {
  291. TMC_DRV_CODES,
  292. TMC_STST,
  293. TMC_OLB,
  294. TMC_OLA,
  295. TMC_S2GB,
  296. TMC_S2GA,
  297. TMC_DRV_OTPW,
  298. TMC_OT,
  299. TMC_STALLGUARD,
  300. TMC_DRV_CS_ACTUAL,
  301. TMC_FSACTIVE,
  302. TMC_SG_RESULT,
  303. TMC_DRV_STATUS_HEX,
  304. TMC_T157,
  305. TMC_T150,
  306. TMC_T143,
  307. TMC_T120,
  308. TMC_STEALTH,
  309. TMC_S2VSB,
  310. TMC_S2VSA
  311. };
  312. enum TMC_get_registers_enum : char {
  313. TMC_AXIS_CODES,
  314. TMC_GET_GCONF,
  315. TMC_GET_IHOLD_IRUN,
  316. TMC_GET_GSTAT,
  317. TMC_GET_IOIN,
  318. TMC_GET_TPOWERDOWN,
  319. TMC_GET_TSTEP,
  320. TMC_GET_TPWMTHRS,
  321. TMC_GET_TCOOLTHRS,
  322. TMC_GET_THIGH,
  323. TMC_GET_CHOPCONF,
  324. TMC_GET_COOLCONF,
  325. TMC_GET_PWMCONF,
  326. TMC_GET_PWM_SCALE,
  327. TMC_GET_DRV_STATUS,
  328. TMC_GET_DRVCONF,
  329. TMC_GET_DRVCTRL,
  330. TMC_GET_DRVSTATUS,
  331. TMC_GET_SGCSCONF,
  332. TMC_GET_SMARTEN
  333. };
  334. template<class TMC>
  335. static void print_vsense(TMC &st) { serialprintPGM(st.vsense() ? PSTR("1=.18") : PSTR("0=.325")); }
  336. #if HAS_DRIVER(TMC2130)
  337. static void tmc_status(TMC2130Stepper &st, const TMC_debug_enum i) {
  338. switch (i) {
  339. case TMC_PWM_SCALE: SERIAL_PRINT(st.PWM_SCALE(), DEC); break;
  340. case TMC_SGT: SERIAL_PRINT(st.sgt(), DEC); break;
  341. case TMC_STEALTHCHOP: serialprintPGM(st.en_pwm_mode() ? PSTR("true") : PSTR("false")); break;
  342. default: break;
  343. }
  344. }
  345. static void _tmc_parse_drv_status(TMC2130Stepper &st, const TMC_drv_status_enum i) {
  346. switch (i) {
  347. case TMC_STALLGUARD: if (st.stallguard()) SERIAL_CHAR('X'); break;
  348. case TMC_SG_RESULT: SERIAL_PRINT(st.sg_result(), DEC); break;
  349. case TMC_FSACTIVE: if (st.fsactive()) SERIAL_CHAR('X'); break;
  350. case TMC_DRV_CS_ACTUAL: SERIAL_PRINT(st.cs_actual(), DEC); break;
  351. default: break;
  352. }
  353. }
  354. #endif
  355. #if HAS_DRIVER(TMC2208)
  356. static void tmc_status(TMC2208Stepper &st, const TMC_debug_enum i) {
  357. switch (i) {
  358. case TMC_PWM_SCALE: SERIAL_PRINT(st.pwm_scale_sum(), DEC); break;
  359. case TMC_STEALTHCHOP: serialprintPGM(st.stealth() ? PSTR("true") : PSTR("false")); break;
  360. case TMC_S2VSA: if (st.s2vsa()) SERIAL_CHAR('X'); break;
  361. case TMC_S2VSB: if (st.s2vsb()) SERIAL_CHAR('X'); break;
  362. default: break;
  363. }
  364. }
  365. static void _tmc_parse_drv_status(TMC2208Stepper &st, const TMC_drv_status_enum i) {
  366. switch (i) {
  367. case TMC_T157: if (st.t157()) SERIAL_CHAR('X'); break;
  368. case TMC_T150: if (st.t150()) SERIAL_CHAR('X'); break;
  369. case TMC_T143: if (st.t143()) SERIAL_CHAR('X'); break;
  370. case TMC_T120: if (st.t120()) SERIAL_CHAR('X'); break;
  371. case TMC_DRV_CS_ACTUAL: SERIAL_PRINT(st.cs_actual(), DEC); break;
  372. default: break;
  373. }
  374. }
  375. #endif
  376. #if HAS_DRIVER(TMC2660)
  377. static void _tmc_parse_drv_status(TMC2660Stepper, const TMC_drv_status_enum) { }
  378. #endif
  379. template <typename TMC>
  380. static void tmc_status(TMC &st, const TMC_debug_enum i, const float spmm) {
  381. SERIAL_CHAR('\t');
  382. switch (i) {
  383. case TMC_CODES: st.printLabel(); break;
  384. case TMC_ENABLED: serialprintPGM(st.isEnabled() ? PSTR("true") : PSTR("false")); break;
  385. case TMC_CURRENT: SERIAL_ECHO(st.getMilliamps()); break;
  386. case TMC_RMS_CURRENT: SERIAL_ECHO(st.rms_current()); break;
  387. case TMC_MAX_CURRENT: SERIAL_PRINT((float)st.rms_current() * 1.41, 0); break;
  388. case TMC_IRUN:
  389. SERIAL_PRINT(st.irun(), DEC);
  390. SERIAL_ECHOPGM("/31");
  391. break;
  392. case TMC_IHOLD:
  393. SERIAL_PRINT(st.ihold(), DEC);
  394. SERIAL_ECHOPGM("/31");
  395. break;
  396. case TMC_CS_ACTUAL:
  397. SERIAL_PRINT(st.cs_actual(), DEC);
  398. SERIAL_ECHOPGM("/31");
  399. break;
  400. case TMC_VSENSE: print_vsense(st); break;
  401. case TMC_MICROSTEPS: SERIAL_ECHO(st.microsteps()); break;
  402. case TMC_TSTEP: {
  403. uint32_t tstep_value = st.TSTEP();
  404. if (tstep_value == 0xFFFFF) SERIAL_ECHOPGM("max");
  405. else SERIAL_ECHO(tstep_value);
  406. }
  407. break;
  408. case TMC_TPWMTHRS: {
  409. uint32_t tpwmthrs_val = st.TPWMTHRS();
  410. SERIAL_ECHO(tpwmthrs_val);
  411. }
  412. break;
  413. case TMC_TPWMTHRS_MMS: {
  414. uint32_t tpwmthrs_val = st.TPWMTHRS();
  415. if (tpwmthrs_val)
  416. SERIAL_ECHO(12650000UL * st.microsteps() / (256 * tpwmthrs_val * spmm));
  417. else
  418. SERIAL_CHAR('-');
  419. }
  420. break;
  421. case TMC_OTPW: serialprintPGM(st.otpw() ? PSTR("true") : PSTR("false")); break;
  422. #if ENABLED(MONITOR_DRIVER_STATUS)
  423. case TMC_OTPW_TRIGGERED: serialprintPGM(st.getOTPW() ? PSTR("true") : PSTR("false")); break;
  424. #endif
  425. case TMC_TOFF: SERIAL_PRINT(st.toff(), DEC); break;
  426. case TMC_TBL: SERIAL_PRINT(st.blank_time(), DEC); break;
  427. case TMC_HEND: SERIAL_PRINT(st.hysteresis_end(), DEC); break;
  428. case TMC_HSTRT: SERIAL_PRINT(st.hysteresis_start(), DEC); break;
  429. default: tmc_status(st, i); break;
  430. }
  431. }
  432. #if HAS_DRIVER(TMC2660)
  433. template<char AXIS_LETTER, char DRIVER_ID>
  434. void tmc_status(TMCMarlin<TMC2660Stepper, AXIS_LETTER, DRIVER_ID> &st, const TMC_debug_enum i, const float) {
  435. SERIAL_CHAR('\t');
  436. switch (i) {
  437. case TMC_CODES: st.printLabel(); break;
  438. case TMC_ENABLED: serialprintPGM(st.isEnabled() ? PSTR("true") : PSTR("false")); break;
  439. case TMC_CURRENT: SERIAL_ECHO(st.getMilliamps()); break;
  440. case TMC_RMS_CURRENT: SERIAL_ECHO(st.rms_current()); break;
  441. case TMC_MAX_CURRENT: SERIAL_PRINT((float)st.rms_current() * 1.41, 0); break;
  442. case TMC_IRUN:
  443. SERIAL_PRINT(st.cs(), DEC);
  444. SERIAL_ECHOPGM("/31");
  445. break;
  446. case TMC_VSENSE: serialprintPGM(st.vsense() ? PSTR("1=.165") : PSTR("0=.310")); break;
  447. case TMC_MICROSTEPS: SERIAL_ECHO(st.microsteps()); break;
  448. //case TMC_OTPW: serialprintPGM(st.otpw() ? PSTR("true") : PSTR("false")); break;
  449. //case TMC_OTPW_TRIGGERED: serialprintPGM(st.getOTPW() ? PSTR("true") : PSTR("false")); break;
  450. case TMC_SGT: SERIAL_PRINT(st.sgt(), DEC); break;
  451. case TMC_TOFF: SERIAL_PRINT(st.toff(), DEC); break;
  452. case TMC_TBL: SERIAL_PRINT(st.blank_time(), DEC); break;
  453. case TMC_HEND: SERIAL_PRINT(st.hysteresis_end(), DEC); break;
  454. case TMC_HSTRT: SERIAL_PRINT(st.hysteresis_start(), DEC); break;
  455. default: break;
  456. }
  457. }
  458. #endif
  459. template <typename TMC>
  460. static void tmc_parse_drv_status(TMC &st, const TMC_drv_status_enum i) {
  461. SERIAL_CHAR('\t');
  462. switch (i) {
  463. case TMC_DRV_CODES: st.printLabel(); break;
  464. case TMC_STST: if (st.stst()) SERIAL_CHAR('X'); break;
  465. case TMC_OLB: if (st.olb()) SERIAL_CHAR('X'); break;
  466. case TMC_OLA: if (st.ola()) SERIAL_CHAR('X'); break;
  467. case TMC_S2GB: if (st.s2gb()) SERIAL_CHAR('X'); break;
  468. case TMC_S2GA: if (st.s2ga()) SERIAL_CHAR('X'); break;
  469. case TMC_DRV_OTPW: if (st.otpw()) SERIAL_CHAR('X'); break;
  470. case TMC_OT: if (st.ot()) SERIAL_CHAR('X'); break;
  471. case TMC_DRV_STATUS_HEX: {
  472. const uint32_t drv_status = st.DRV_STATUS();
  473. SERIAL_CHAR('\t');
  474. st.printLabel();
  475. SERIAL_CHAR('\t');
  476. print_hex_long(drv_status, ':');
  477. if (drv_status == 0xFFFFFFFF || drv_status == 0) SERIAL_ECHOPGM("\t Bad response!");
  478. SERIAL_EOL();
  479. break;
  480. }
  481. default: _tmc_parse_drv_status(st, i); break;
  482. }
  483. }
  484. static void tmc_debug_loop(const TMC_debug_enum i, const bool print_x, const bool print_y, const bool print_z, const bool print_e) {
  485. if (print_x) {
  486. #if AXIS_IS_TMC(X)
  487. tmc_status(stepperX, i, planner.settings.axis_steps_per_mm[X_AXIS]);
  488. #endif
  489. #if AXIS_IS_TMC(X2)
  490. tmc_status(stepperX2, i, planner.settings.axis_steps_per_mm[X_AXIS]);
  491. #endif
  492. }
  493. if (print_y) {
  494. #if AXIS_IS_TMC(Y)
  495. tmc_status(stepperY, i, planner.settings.axis_steps_per_mm[Y_AXIS]);
  496. #endif
  497. #if AXIS_IS_TMC(Y2)
  498. tmc_status(stepperY2, i, planner.settings.axis_steps_per_mm[Y_AXIS]);
  499. #endif
  500. }
  501. if (print_z) {
  502. #if AXIS_IS_TMC(Z)
  503. tmc_status(stepperZ, i, planner.settings.axis_steps_per_mm[Z_AXIS]);
  504. #endif
  505. #if AXIS_IS_TMC(Z2)
  506. tmc_status(stepperZ2, i, planner.settings.axis_steps_per_mm[Z_AXIS]);
  507. #endif
  508. #if AXIS_IS_TMC(Z3)
  509. tmc_status(stepperZ3, i, planner.settings.axis_steps_per_mm[Z_AXIS]);
  510. #endif
  511. }
  512. if (print_e) {
  513. #if AXIS_IS_TMC(E0)
  514. tmc_status(stepperE0, i, planner.settings.axis_steps_per_mm[E_AXIS]);
  515. #endif
  516. #if AXIS_IS_TMC(E1)
  517. tmc_status(stepperE1, i, planner.settings.axis_steps_per_mm[E_AXIS
  518. #if ENABLED(DISTINCT_E_FACTORS)
  519. + 1
  520. #endif
  521. ]);
  522. #endif
  523. #if AXIS_IS_TMC(E2)
  524. tmc_status(stepperE2, i, planner.settings.axis_steps_per_mm[E_AXIS
  525. #if ENABLED(DISTINCT_E_FACTORS)
  526. + 2
  527. #endif
  528. ]);
  529. #endif
  530. #if AXIS_IS_TMC(E3)
  531. tmc_status(stepperE3, i, planner.settings.axis_steps_per_mm[E_AXIS
  532. #if ENABLED(DISTINCT_E_FACTORS)
  533. + 3
  534. #endif
  535. ]);
  536. #endif
  537. #if AXIS_IS_TMC(E4)
  538. tmc_status(stepperE4, i, planner.settings.axis_steps_per_mm[E_AXIS
  539. #if ENABLED(DISTINCT_E_FACTORS)
  540. + 4
  541. #endif
  542. ]);
  543. #endif
  544. #if AXIS_IS_TMC(E5)
  545. tmc_status(stepperE5, i, planner.settings.axis_steps_per_mm[E_AXIS
  546. #if ENABLED(DISTINCT_E_FACTORS)
  547. + 5
  548. #endif
  549. ]);
  550. #endif
  551. }
  552. SERIAL_EOL();
  553. }
  554. static void drv_status_loop(const TMC_drv_status_enum i, const bool print_x, const bool print_y, const bool print_z, const bool print_e) {
  555. if (print_x) {
  556. #if AXIS_IS_TMC(X)
  557. tmc_parse_drv_status(stepperX, i);
  558. #endif
  559. #if AXIS_IS_TMC(X2)
  560. tmc_parse_drv_status(stepperX2, i);
  561. #endif
  562. }
  563. if (print_y) {
  564. #if AXIS_IS_TMC(Y)
  565. tmc_parse_drv_status(stepperY, i);
  566. #endif
  567. #if AXIS_IS_TMC(Y2)
  568. tmc_parse_drv_status(stepperY2, i);
  569. #endif
  570. }
  571. if (print_z) {
  572. #if AXIS_IS_TMC(Z)
  573. tmc_parse_drv_status(stepperZ, i);
  574. #endif
  575. #if AXIS_IS_TMC(Z2)
  576. tmc_parse_drv_status(stepperZ2, i);
  577. #endif
  578. #if AXIS_IS_TMC(Z3)
  579. tmc_parse_drv_status(stepperZ3, i);
  580. #endif
  581. }
  582. if (print_e) {
  583. #if AXIS_IS_TMC(E0)
  584. tmc_parse_drv_status(stepperE0, i);
  585. #endif
  586. #if AXIS_IS_TMC(E1)
  587. tmc_parse_drv_status(stepperE1, i);
  588. #endif
  589. #if AXIS_IS_TMC(E2)
  590. tmc_parse_drv_status(stepperE2, i);
  591. #endif
  592. #if AXIS_IS_TMC(E3)
  593. tmc_parse_drv_status(stepperE3, i);
  594. #endif
  595. #if AXIS_IS_TMC(E4)
  596. tmc_parse_drv_status(stepperE4, i);
  597. #endif
  598. #if AXIS_IS_TMC(E5)
  599. tmc_parse_drv_status(stepperE5, i);
  600. #endif
  601. }
  602. SERIAL_EOL();
  603. }
  604. /**
  605. * M122 report functions
  606. */
  607. void tmc_report_all(bool print_x, const bool print_y, const bool print_z, const bool print_e) {
  608. #define TMC_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_debug_loop(ITEM, print_x, print_y, print_z, print_e); }while(0)
  609. #define DRV_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); drv_status_loop(ITEM, print_x, print_y, print_z, print_e); }while(0)
  610. TMC_REPORT("\t", TMC_CODES);
  611. TMC_REPORT("Enabled\t", TMC_ENABLED);
  612. TMC_REPORT("Set current", TMC_CURRENT);
  613. TMC_REPORT("RMS current", TMC_RMS_CURRENT);
  614. TMC_REPORT("MAX current", TMC_MAX_CURRENT);
  615. TMC_REPORT("Run current", TMC_IRUN);
  616. TMC_REPORT("Hold current", TMC_IHOLD);
  617. TMC_REPORT("CS actual\t", TMC_CS_ACTUAL);
  618. TMC_REPORT("PWM scale", TMC_PWM_SCALE);
  619. TMC_REPORT("vsense\t", TMC_VSENSE);
  620. TMC_REPORT("stealthChop", TMC_STEALTHCHOP);
  621. TMC_REPORT("msteps\t", TMC_MICROSTEPS);
  622. TMC_REPORT("tstep\t", TMC_TSTEP);
  623. TMC_REPORT("pwm\nthreshold\t", TMC_TPWMTHRS);
  624. TMC_REPORT("[mm/s]\t", TMC_TPWMTHRS_MMS);
  625. TMC_REPORT("OT prewarn", TMC_OTPW);
  626. #if ENABLED(MONITOR_DRIVER_STATUS)
  627. TMC_REPORT("OT prewarn has\n"
  628. "been triggered", TMC_OTPW_TRIGGERED);
  629. #endif
  630. TMC_REPORT("off time\t", TMC_TOFF);
  631. TMC_REPORT("blank time", TMC_TBL);
  632. TMC_REPORT("hysteresis\n-end\t", TMC_HEND);
  633. TMC_REPORT("-start\t", TMC_HSTRT);
  634. TMC_REPORT("Stallguard thrs", TMC_SGT);
  635. DRV_REPORT("DRVSTATUS", TMC_DRV_CODES);
  636. #if HAS_DRIVER(TMC2130)
  637. DRV_REPORT("stallguard\t", TMC_STALLGUARD);
  638. DRV_REPORT("sg_result\t", TMC_SG_RESULT);
  639. DRV_REPORT("fsactive\t", TMC_FSACTIVE);
  640. #endif
  641. DRV_REPORT("stst\t", TMC_STST);
  642. DRV_REPORT("olb\t", TMC_OLB);
  643. DRV_REPORT("ola\t", TMC_OLA);
  644. DRV_REPORT("s2gb\t", TMC_S2GB);
  645. DRV_REPORT("s2ga\t", TMC_S2GA);
  646. DRV_REPORT("otpw\t", TMC_DRV_OTPW);
  647. DRV_REPORT("ot\t", TMC_OT);
  648. #if HAS_DRIVER(TMC2208)
  649. DRV_REPORT("157C\t", TMC_T157);
  650. DRV_REPORT("150C\t", TMC_T150);
  651. DRV_REPORT("143C\t", TMC_T143);
  652. DRV_REPORT("120C\t", TMC_T120);
  653. DRV_REPORT("s2vsa\t", TMC_S2VSA);
  654. DRV_REPORT("s2vsb\t", TMC_S2VSB);
  655. #endif
  656. DRV_REPORT("Driver registers:\n",TMC_DRV_STATUS_HEX);
  657. SERIAL_EOL();
  658. }
  659. #define PRINT_TMC_REGISTER(REG_CASE) case TMC_GET_##REG_CASE: print_hex_long(st.REG_CASE(), ':'); break
  660. #if HAS_DRIVER(TMC2130)
  661. static void tmc_get_ic_registers(TMC2130Stepper &st, const TMC_get_registers_enum i) {
  662. switch (i) {
  663. PRINT_TMC_REGISTER(TCOOLTHRS);
  664. PRINT_TMC_REGISTER(THIGH);
  665. PRINT_TMC_REGISTER(COOLCONF);
  666. default: SERIAL_CHAR('\t'); break;
  667. }
  668. }
  669. #endif
  670. #if HAS_DRIVER(TMC2208)
  671. static void tmc_get_ic_registers(TMC2208Stepper, const TMC_get_registers_enum) { SERIAL_CHAR('\t'); }
  672. #endif
  673. #if HAS_TRINAMIC
  674. template<class TMC>
  675. static void tmc_get_registers(TMC &st, const TMC_get_registers_enum i) {
  676. switch (i) {
  677. case TMC_AXIS_CODES: SERIAL_CHAR('\t'); st.printLabel(); break;
  678. PRINT_TMC_REGISTER(GCONF);
  679. PRINT_TMC_REGISTER(IHOLD_IRUN);
  680. PRINT_TMC_REGISTER(GSTAT);
  681. PRINT_TMC_REGISTER(IOIN);
  682. PRINT_TMC_REGISTER(TPOWERDOWN);
  683. PRINT_TMC_REGISTER(TSTEP);
  684. PRINT_TMC_REGISTER(TPWMTHRS);
  685. PRINT_TMC_REGISTER(CHOPCONF);
  686. PRINT_TMC_REGISTER(PWMCONF);
  687. PRINT_TMC_REGISTER(PWM_SCALE);
  688. PRINT_TMC_REGISTER(DRV_STATUS);
  689. default: tmc_get_ic_registers(st, i); break;
  690. }
  691. SERIAL_CHAR('\t');
  692. }
  693. #endif
  694. #if HAS_DRIVER(TMC2660)
  695. template <char AXIS_LETTER, char DRIVER_ID>
  696. static void tmc_get_registers(TMCMarlin<TMC2660Stepper, AXIS_LETTER, DRIVER_ID> &st, const TMC_get_registers_enum i) {
  697. switch (i) {
  698. case TMC_AXIS_CODES: SERIAL_CHAR('\t'); st.printLabel(); break;
  699. PRINT_TMC_REGISTER(DRVCONF);
  700. PRINT_TMC_REGISTER(DRVCTRL);
  701. PRINT_TMC_REGISTER(CHOPCONF);
  702. PRINT_TMC_REGISTER(DRVSTATUS);
  703. PRINT_TMC_REGISTER(SGCSCONF);
  704. PRINT_TMC_REGISTER(SMARTEN);
  705. default: SERIAL_CHAR('\t'); break;
  706. }
  707. SERIAL_CHAR('\t');
  708. }
  709. #endif
  710. static void tmc_get_registers(TMC_get_registers_enum i, const bool print_x, const bool print_y, const bool print_z, const bool print_e) {
  711. if (print_x) {
  712. #if AXIS_IS_TMC(X)
  713. tmc_get_registers(stepperX, i);
  714. #endif
  715. #if AXIS_IS_TMC(X2)
  716. tmc_get_registers(stepperX2, i);
  717. #endif
  718. }
  719. if (print_y) {
  720. #if AXIS_IS_TMC(Y)
  721. tmc_get_registers(stepperY, i);
  722. #endif
  723. #if AXIS_IS_TMC(Y2)
  724. tmc_get_registers(stepperY2, i);
  725. #endif
  726. }
  727. if (print_z) {
  728. #if AXIS_IS_TMC(Z)
  729. tmc_get_registers(stepperZ, i);
  730. #endif
  731. #if AXIS_IS_TMC(Z2)
  732. tmc_get_registers(stepperZ2, i);
  733. #endif
  734. #if AXIS_IS_TMC(Z3)
  735. tmc_get_registers(stepperZ3, i);
  736. #endif
  737. }
  738. if (print_e) {
  739. #if AXIS_IS_TMC(E0)
  740. tmc_get_registers(stepperE0, i);
  741. #endif
  742. #if AXIS_IS_TMC(E1)
  743. tmc_get_registers(stepperE1, i);
  744. #endif
  745. #if AXIS_IS_TMC(E2)
  746. tmc_get_registers(stepperE2, i);
  747. #endif
  748. #if AXIS_IS_TMC(E3)
  749. tmc_get_registers(stepperE3, i);
  750. #endif
  751. #if AXIS_IS_TMC(E4)
  752. tmc_get_registers(stepperE4, i);
  753. #endif
  754. #if AXIS_IS_TMC(E5)
  755. tmc_get_registers(stepperE5, i);
  756. #endif
  757. }
  758. SERIAL_EOL();
  759. }
  760. void tmc_get_registers(bool print_x, bool print_y, bool print_z, bool print_e) {
  761. #define _TMC_GET_REG(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_get_registers(ITEM, print_x, print_y, print_z, print_e); }while(0)
  762. #define TMC_GET_REG(NAME, TABS) _TMC_GET_REG(STRINGIFY(NAME) TABS, TMC_GET_##NAME)
  763. _TMC_GET_REG("\t", TMC_AXIS_CODES);
  764. TMC_GET_REG(GCONF, "\t\t");
  765. TMC_GET_REG(IHOLD_IRUN, "\t");
  766. TMC_GET_REG(GSTAT, "\t\t");
  767. TMC_GET_REG(IOIN, "\t\t");
  768. TMC_GET_REG(TPOWERDOWN, "\t");
  769. TMC_GET_REG(TSTEP, "\t\t");
  770. TMC_GET_REG(TPWMTHRS, "\t");
  771. TMC_GET_REG(TCOOLTHRS, "\t");
  772. TMC_GET_REG(THIGH, "\t\t");
  773. TMC_GET_REG(CHOPCONF, "\t");
  774. TMC_GET_REG(COOLCONF, "\t");
  775. TMC_GET_REG(PWMCONF, "\t");
  776. TMC_GET_REG(PWM_SCALE, "\t");
  777. TMC_GET_REG(DRV_STATUS, "\t");
  778. }
  779. #endif // TMC_DEBUG
  780. #if USE_SENSORLESS
  781. bool tmc_enable_stallguard(TMC2130Stepper &st) {
  782. bool stealthchop_was_enabled = st.en_pwm_mode();
  783. st.TCOOLTHRS(0xFFFFF);
  784. st.en_pwm_mode(false);
  785. st.diag1_stall(true);
  786. return stealthchop_was_enabled;
  787. }
  788. void tmc_disable_stallguard(TMC2130Stepper &st, const bool restore_stealth) {
  789. st.TCOOLTHRS(0);
  790. st.en_pwm_mode(restore_stealth);
  791. st.diag1_stall(false);
  792. }
  793. bool tmc_enable_stallguard(TMC2660Stepper) {
  794. // TODO
  795. return false;
  796. }
  797. void tmc_disable_stallguard(TMC2660Stepper, const bool) {};
  798. #endif // USE_SENSORLESS
  799. #if TMC_HAS_SPI
  800. #define SET_CS_PIN(st) OUT_WRITE(st##_CS_PIN, HIGH)
  801. void tmc_init_cs_pins() {
  802. #if AXIS_HAS_SPI(X)
  803. SET_CS_PIN(X);
  804. #endif
  805. #if AXIS_HAS_SPI(Y)
  806. SET_CS_PIN(Y);
  807. #endif
  808. #if AXIS_HAS_SPI(Z)
  809. SET_CS_PIN(Z);
  810. #endif
  811. #if AXIS_HAS_SPI(X2)
  812. SET_CS_PIN(X2);
  813. #endif
  814. #if AXIS_HAS_SPI(Y2)
  815. SET_CS_PIN(Y2);
  816. #endif
  817. #if AXIS_HAS_SPI(Z2)
  818. SET_CS_PIN(Z2);
  819. #endif
  820. #if AXIS_HAS_SPI(Z3)
  821. SET_CS_PIN(Z3);
  822. #endif
  823. #if AXIS_HAS_SPI(E0)
  824. SET_CS_PIN(E0);
  825. #endif
  826. #if AXIS_HAS_SPI(E1)
  827. SET_CS_PIN(E1);
  828. #endif
  829. #if AXIS_HAS_SPI(E2)
  830. SET_CS_PIN(E2);
  831. #endif
  832. #if AXIS_HAS_SPI(E3)
  833. SET_CS_PIN(E3);
  834. #endif
  835. #if AXIS_HAS_SPI(E4)
  836. SET_CS_PIN(E4);
  837. #endif
  838. #if AXIS_HAS_SPI(E5)
  839. SET_CS_PIN(E5);
  840. #endif
  841. }
  842. #endif // TMC_HAS_SPI
  843. template<typename TMC>
  844. static bool test_connection(TMC &st) {
  845. SERIAL_ECHOPGM("Testing ");
  846. st.printLabel();
  847. SERIAL_ECHOPGM(" connection... ");
  848. const uint8_t test_result = st.test_connection();
  849. if (test_result > 0) SERIAL_ECHOPGM("Error: All ");
  850. const char *stat;
  851. switch (test_result) {
  852. default:
  853. case 0: stat = PSTR("OK"); break;
  854. case 1: stat = PSTR("HIGH"); break;
  855. case 2: stat = PSTR("LOW"); break;
  856. }
  857. serialprintPGM(stat);
  858. SERIAL_EOL();
  859. return test_result;
  860. }
  861. void test_tmc_connection(const bool test_x, const bool test_y, const bool test_z, const bool test_e) {
  862. uint8_t axis_connection = 0;
  863. if (test_x) {
  864. #if AXIS_IS_TMC(X)
  865. axis_connection += test_connection(stepperX);
  866. #endif
  867. #if AXIS_IS_TMC(X2)
  868. axis_connection += test_connection(stepperX2);
  869. #endif
  870. }
  871. if (test_y) {
  872. #if AXIS_IS_TMC(Y)
  873. axis_connection += test_connection(stepperY);
  874. #endif
  875. #if AXIS_IS_TMC(Y2)
  876. axis_connection += test_connection(stepperY2);
  877. #endif
  878. }
  879. if (test_z) {
  880. #if AXIS_IS_TMC(Z)
  881. axis_connection += test_connection(stepperZ);
  882. #endif
  883. #if AXIS_IS_TMC(Z2)
  884. axis_connection += test_connection(stepperZ2);
  885. #endif
  886. #if AXIS_IS_TMC(Z3)
  887. axis_connection += test_connection(stepperZ3);
  888. #endif
  889. }
  890. if (test_e) {
  891. #if AXIS_IS_TMC(E0)
  892. axis_connection += test_connection(stepperE0);
  893. #endif
  894. #if AXIS_IS_TMC(E1)
  895. axis_connection += test_connection(stepperE1);
  896. #endif
  897. #if AXIS_IS_TMC(E2)
  898. axis_connection += test_connection(stepperE2);
  899. #endif
  900. #if AXIS_IS_TMC(E3)
  901. axis_connection += test_connection(stepperE3);
  902. #endif
  903. #if AXIS_IS_TMC(E4)
  904. axis_connection += test_connection(stepperE4);
  905. #endif
  906. #if AXIS_IS_TMC(E5)
  907. axis_connection += test_connection(stepperE5);
  908. #endif
  909. }
  910. if (axis_connection) ui.set_status_P(PSTR("TMC CONNECTION ERROR"));
  911. }
  912. #if HAS_LCD_MENU
  913. void init_tmc_section() {
  914. #if AXIS_IS_TMC(X)
  915. stepperX.init_lcd_variables(X_AXIS);
  916. #endif
  917. #if AXIS_IS_TMC(Y)
  918. stepperY.init_lcd_variables(Y_AXIS);
  919. #endif
  920. #if AXIS_IS_TMC(Z)
  921. stepperZ.init_lcd_variables(Z_AXIS);
  922. #endif
  923. #if AXIS_IS_TMC(X2)
  924. stepperX2.init_lcd_variables(X_AXIS);
  925. #endif
  926. #if AXIS_IS_TMC(Y2)
  927. stepperY2.init_lcd_variables(Y_AXIS);
  928. #endif
  929. #if AXIS_IS_TMC(Z2)
  930. stepperZ2.init_lcd_variables(Z_AXIS);
  931. #endif
  932. #if AXIS_IS_TMC(Z3)
  933. stepperZ3.init_lcd_variables(Z_AXIS);
  934. #endif
  935. #if AXIS_IS_TMC(E0)
  936. stepperE0.init_lcd_variables(E_AXIS);
  937. #endif
  938. #if AXIS_IS_TMC(E1)
  939. stepperE1.init_lcd_variables(E_AXIS_N(1));
  940. #endif
  941. #if AXIS_IS_TMC(E2)
  942. stepperE2.init_lcd_variables(E_AXIS_N(2));
  943. #endif
  944. #if AXIS_IS_TMC(E3)
  945. stepperE3.init_lcd_variables(E_AXIS_N(3));
  946. #endif
  947. #if AXIS_IS_TMC(E4)
  948. stepperE4.init_lcd_variables(E_AXIS_N(4));
  949. #endif
  950. #if AXIS_IS_TMC(E5)
  951. stepperE5.init_lcd_variables(E_AXIS_N(5));
  952. #endif
  953. }
  954. #endif
  955. #endif // HAS_TRINAMIC