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.

M911-M914.cpp 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. /**
  2. * Marlin 3D Printer Firmware
  3. * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
  20. *
  21. */
  22. #include "../../../inc/MarlinConfig.h"
  23. #if HAS_TRINAMIC_CONFIG
  24. #include "../../gcode.h"
  25. #include "../../../feature/tmc_util.h"
  26. #include "../../../module/stepper/indirection.h"
  27. #include "../../../module/planner.h"
  28. #include "../../queue.h"
  29. #if ENABLED(MONITOR_DRIVER_STATUS)
  30. #define M91x_USE(ST) (AXIS_DRIVER_TYPE(ST, TMC2130) || AXIS_DRIVER_TYPE(ST, TMC2160) || AXIS_DRIVER_TYPE(ST, TMC2208) || AXIS_DRIVER_TYPE(ST, TMC2209) || AXIS_DRIVER_TYPE(ST, TMC2660) || AXIS_DRIVER_TYPE(ST, TMC5130) || AXIS_DRIVER_TYPE(ST, TMC5160))
  31. #define M91x_USE_E(N) (E_STEPPERS > N && M91x_USE(E##N))
  32. #if M91x_USE(X) || M91x_USE(X2)
  33. #define M91x_SOME_X 1
  34. #endif
  35. #if HAS_Y_AXIS && (M91x_USE(Y) || M91x_USE(Y2))
  36. #define M91x_SOME_Y 1
  37. #endif
  38. #if HAS_Z_AXIS && (M91x_USE(Z) || M91x_USE(Z2) || M91x_USE(Z3) || M91x_USE(Z4))
  39. #define M91x_SOME_Z 1
  40. #endif
  41. #if HAS_I_AXIS && M91x_USE(I)
  42. #define M91x_USE_I 1
  43. #endif
  44. #if HAS_J_AXIS && M91x_USE(J)
  45. #define M91x_USE_J 1
  46. #endif
  47. #if HAS_K_AXIS && M91x_USE(K)
  48. #define M91x_USE_K 1
  49. #endif
  50. #if HAS_U_AXIS && M91x_USE(U)
  51. #define M91x_USE_U 1
  52. #endif
  53. #if HAS_V_AXIS && M91x_USE(V)
  54. #define M91x_USE_V 1
  55. #endif
  56. #if HAS_W_AXIS && M91x_USE(W)
  57. #define M91x_USE_W 1
  58. #endif
  59. #if M91x_USE_E(0) || M91x_USE_E(1) || M91x_USE_E(2) || M91x_USE_E(3) || M91x_USE_E(4) || M91x_USE_E(5) || M91x_USE_E(6) || M91x_USE_E(7)
  60. #define M91x_SOME_E 1
  61. #endif
  62. #if !M91x_SOME_X && !M91x_SOME_Y && !M91x_SOME_Z && !M91x_USE_I && !M91x_USE_J && !M91x_USE_K && !M91x_USE_U && !M91x_USE_V && !M91x_USE_W && !M91x_SOME_E
  63. #error "MONITOR_DRIVER_STATUS requires at least one TMC2130, 2160, 2208, 2209, 2660, 5130, or 5160."
  64. #endif
  65. template<typename TMC>
  66. static void tmc_report_otpw(TMC &st) {
  67. st.printLabel();
  68. SERIAL_ECHOPGM(" temperature prewarn triggered: ");
  69. serialprint_truefalse(st.getOTPW());
  70. SERIAL_EOL();
  71. }
  72. template<typename TMC>
  73. static void tmc_clear_otpw(TMC &st) {
  74. st.clear_otpw();
  75. st.printLabel();
  76. SERIAL_ECHOLNPGM(" prewarn flag cleared");
  77. }
  78. /**
  79. * M911: Report TMC stepper driver overtemperature pre-warn flag
  80. * This flag is held by the library, persisting until cleared by M912
  81. */
  82. void GcodeSuite::M911() {
  83. #if M91x_USE(X)
  84. tmc_report_otpw(stepperX);
  85. #endif
  86. #if M91x_USE(X2)
  87. tmc_report_otpw(stepperX2);
  88. #endif
  89. #if M91x_USE(Y)
  90. tmc_report_otpw(stepperY);
  91. #endif
  92. #if M91x_USE(Y2)
  93. tmc_report_otpw(stepperY2);
  94. #endif
  95. #if M91x_USE(Z)
  96. tmc_report_otpw(stepperZ);
  97. #endif
  98. #if M91x_USE(Z2)
  99. tmc_report_otpw(stepperZ2);
  100. #endif
  101. #if M91x_USE(Z3)
  102. tmc_report_otpw(stepperZ3);
  103. #endif
  104. #if M91x_USE(Z4)
  105. tmc_report_otpw(stepperZ4);
  106. #endif
  107. TERN_(M91x_USE_I, tmc_report_otpw(stepperI));
  108. TERN_(M91x_USE_J, tmc_report_otpw(stepperJ));
  109. TERN_(M91x_USE_K, tmc_report_otpw(stepperK));
  110. TERN_(M91x_USE_U, tmc_report_otpw(stepperU));
  111. TERN_(M91x_USE_V, tmc_report_otpw(stepperV));
  112. TERN_(M91x_USE_W, tmc_report_otpw(stepperW));
  113. #if M91x_USE_E(0)
  114. tmc_report_otpw(stepperE0);
  115. #endif
  116. #if M91x_USE_E(1)
  117. tmc_report_otpw(stepperE1);
  118. #endif
  119. #if M91x_USE_E(2)
  120. tmc_report_otpw(stepperE2);
  121. #endif
  122. #if M91x_USE_E(3)
  123. tmc_report_otpw(stepperE3);
  124. #endif
  125. #if M91x_USE_E(4)
  126. tmc_report_otpw(stepperE4);
  127. #endif
  128. #if M91x_USE_E(5)
  129. tmc_report_otpw(stepperE5);
  130. #endif
  131. #if M91x_USE_E(6)
  132. tmc_report_otpw(stepperE6);
  133. #endif
  134. #if M91x_USE_E(7)
  135. tmc_report_otpw(stepperE7);
  136. #endif
  137. }
  138. /**
  139. * M912: Clear TMC stepper driver overtemperature pre-warn flag held by the library
  140. * Specify one or more axes with X, Y, Z, X1, Y1, Z1, X2, Y2, Z2, Z3, Z4, A, B, C, U, V, W, and E[index].
  141. * If no axes are given, clear all.
  142. *
  143. * Examples:
  144. * M912 X ; clear X and X2
  145. * M912 X1 ; clear X1 only
  146. * M912 X2 ; clear X2 only
  147. * M912 X E ; clear X, X2, and all E
  148. * M912 E1 ; clear E1 only
  149. */
  150. void GcodeSuite::M912() {
  151. const bool hasX = TERN0(M91x_SOME_X, parser.seen(axis_codes.x)),
  152. hasY = TERN0(M91x_SOME_Y, parser.seen(axis_codes.y)),
  153. hasZ = TERN0(M91x_SOME_Z, parser.seen(axis_codes.z)),
  154. hasI = TERN0(M91x_USE_I, parser.seen(axis_codes.i)),
  155. hasJ = TERN0(M91x_USE_J, parser.seen(axis_codes.j)),
  156. hasK = TERN0(M91x_USE_K, parser.seen(axis_codes.k)),
  157. hasU = TERN0(M91x_USE_U, parser.seen(axis_codes.u)),
  158. hasV = TERN0(M91x_USE_V, parser.seen(axis_codes.v)),
  159. hasW = TERN0(M91x_USE_W, parser.seen(axis_codes.w)),
  160. hasE = TERN0(M91x_SOME_E, parser.seen(axis_codes.e));
  161. const bool hasNone = !hasE && !hasX && !hasY && !hasZ && !hasI && !hasJ && !hasK && !hasU && !hasV && !hasW;
  162. #if M91x_SOME_X
  163. const int8_t xval = int8_t(parser.byteval(axis_codes.x, 0xFF));
  164. #if M91x_USE(X)
  165. if (hasNone || xval == 1 || (hasX && xval < 0)) tmc_clear_otpw(stepperX);
  166. #endif
  167. #if M91x_USE(X2)
  168. if (hasNone || xval == 2 || (hasX && xval < 0)) tmc_clear_otpw(stepperX2);
  169. #endif
  170. #endif
  171. #if M91x_SOME_Y
  172. const int8_t yval = int8_t(parser.byteval(axis_codes.y, 0xFF));
  173. #if M91x_USE(Y)
  174. if (hasNone || yval == 1 || (hasY && yval < 0)) tmc_clear_otpw(stepperY);
  175. #endif
  176. #if M91x_USE(Y2)
  177. if (hasNone || yval == 2 || (hasY && yval < 0)) tmc_clear_otpw(stepperY2);
  178. #endif
  179. #endif
  180. #if M91x_SOME_Z
  181. const int8_t zval = int8_t(parser.byteval(axis_codes.z, 0xFF));
  182. #if M91x_USE(Z)
  183. if (hasNone || zval == 1 || (hasZ && zval < 0)) tmc_clear_otpw(stepperZ);
  184. #endif
  185. #if M91x_USE(Z2)
  186. if (hasNone || zval == 2 || (hasZ && zval < 0)) tmc_clear_otpw(stepperZ2);
  187. #endif
  188. #if M91x_USE(Z3)
  189. if (hasNone || zval == 3 || (hasZ && zval < 0)) tmc_clear_otpw(stepperZ3);
  190. #endif
  191. #if M91x_USE(Z4)
  192. if (hasNone || zval == 4 || (hasZ && zval < 0)) tmc_clear_otpw(stepperZ4);
  193. #endif
  194. #endif
  195. #if M91x_USE_I
  196. const int8_t ival = int8_t(parser.byteval(axis_codes.i, 0xFF));
  197. if (hasNone || ival == 1 || (hasI && ival < 0)) tmc_clear_otpw(stepperI);
  198. #endif
  199. #if M91x_USE_J
  200. const int8_t jval = int8_t(parser.byteval(axis_codes.j, 0xFF));
  201. if (hasNone || jval == 1 || (hasJ && jval < 0)) tmc_clear_otpw(stepperJ);
  202. #endif
  203. #if M91x_USE_K
  204. const int8_t kval = int8_t(parser.byteval(axis_codes.k, 0xFF));
  205. if (hasNone || kval == 1 || (hasK && kval < 0)) tmc_clear_otpw(stepperK);
  206. #endif
  207. #if M91x_USE_U
  208. const int8_t uval = int8_t(parser.byteval(axis_codes.u, 0xFF));
  209. if (hasNone || uval == 1 || (hasU && uval < 0)) tmc_clear_otpw(stepperU);
  210. #endif
  211. #if M91x_USE_V
  212. const int8_t vval = int8_t(parser.byteval(axis_codes.v, 0xFF));
  213. if (hasNone || vval == 1 || (hasV && vval < 0)) tmc_clear_otpw(stepperV);
  214. #endif
  215. #if M91x_USE_W
  216. const int8_t wval = int8_t(parser.byteval(axis_codes.w, 0xFF));
  217. if (hasNone || wval == 1 || (hasW && wval < 0)) tmc_clear_otpw(stepperW);
  218. #endif
  219. #if M91x_SOME_E
  220. const int8_t eval = int8_t(parser.byteval(axis_codes.e, 0xFF));
  221. #if M91x_USE_E(0)
  222. if (hasNone || eval == 0 || (hasE && eval < 0)) tmc_clear_otpw(stepperE0);
  223. #endif
  224. #if M91x_USE_E(1)
  225. if (hasNone || eval == 1 || (hasE && eval < 0)) tmc_clear_otpw(stepperE1);
  226. #endif
  227. #if M91x_USE_E(2)
  228. if (hasNone || eval == 2 || (hasE && eval < 0)) tmc_clear_otpw(stepperE2);
  229. #endif
  230. #if M91x_USE_E(3)
  231. if (hasNone || eval == 3 || (hasE && eval < 0)) tmc_clear_otpw(stepperE3);
  232. #endif
  233. #if M91x_USE_E(4)
  234. if (hasNone || eval == 4 || (hasE && eval < 0)) tmc_clear_otpw(stepperE4);
  235. #endif
  236. #if M91x_USE_E(5)
  237. if (hasNone || eval == 5 || (hasE && eval < 0)) tmc_clear_otpw(stepperE5);
  238. #endif
  239. #if M91x_USE_E(6)
  240. if (hasNone || eval == 6 || (hasE && eval < 0)) tmc_clear_otpw(stepperE6);
  241. #endif
  242. #if M91x_USE_E(7)
  243. if (hasNone || eval == 7 || (hasE && eval < 0)) tmc_clear_otpw(stepperE7);
  244. #endif
  245. #endif
  246. }
  247. #endif // MONITOR_DRIVER_STATUS
  248. #if ENABLED(HYBRID_THRESHOLD)
  249. template<typename TMC>
  250. static void tmc_print_pwmthrs(TMC &st) {
  251. st.printLabel();
  252. SERIAL_ECHOLNPGM(" stealthChop max speed: ", st.get_pwm_thrs());
  253. }
  254. /**
  255. * M913: Set HYBRID_THRESHOLD speed.
  256. */
  257. void GcodeSuite::M913() {
  258. #define TMC_SAY_PWMTHRS(A,Q) tmc_print_pwmthrs(stepper##Q)
  259. #define TMC_SET_PWMTHRS(A,Q) stepper##Q.set_pwm_thrs(value)
  260. #define TMC_SAY_PWMTHRS_E(E) tmc_print_pwmthrs(stepperE##E)
  261. #define TMC_SET_PWMTHRS_E(E) stepperE##E.set_pwm_thrs(value)
  262. bool report = true;
  263. #if AXIS_IS_TMC(X2) || AXIS_IS_TMC(Y2) || AXIS_IS_TMC(Z2) || AXIS_IS_TMC(Z3) || AXIS_IS_TMC(Z4)
  264. const uint8_t index = parser.byteval('I');
  265. #elif AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z)
  266. constexpr uint8_t index = 0;
  267. #endif
  268. LOOP_LOGICAL_AXES(i) if (int32_t value = parser.longval(AXIS_CHAR(i))) {
  269. report = false;
  270. switch (i) {
  271. #if X_HAS_STEALTHCHOP || X2_HAS_STEALTHCHOP
  272. case X_AXIS:
  273. TERN_(X_HAS_STEALTHCHOP, if (index < 2) TMC_SET_PWMTHRS(X,X));
  274. TERN_(X2_HAS_STEALTHCHOP, if (!index || index == 2) TMC_SET_PWMTHRS(X,X2));
  275. break;
  276. #endif
  277. #if Y_HAS_STEALTHCHOP || Y2_HAS_STEALTHCHOP
  278. case Y_AXIS:
  279. TERN_(Y_HAS_STEALTHCHOP, if (index < 2) TMC_SET_PWMTHRS(Y,Y));
  280. TERN_(Y2_HAS_STEALTHCHOP, if (!index || index == 2) TMC_SET_PWMTHRS(Y,Y2));
  281. break;
  282. #endif
  283. #if Z_HAS_STEALTHCHOP || Z2_HAS_STEALTHCHOP || Z3_HAS_STEALTHCHOP || Z4_HAS_STEALTHCHOP
  284. case Z_AXIS:
  285. TERN_(Z_HAS_STEALTHCHOP, if (index < 2) TMC_SET_PWMTHRS(Z,Z));
  286. TERN_(Z2_HAS_STEALTHCHOP, if (!index || index == 2) TMC_SET_PWMTHRS(Z,Z2));
  287. TERN_(Z3_HAS_STEALTHCHOP, if (!index || index == 3) TMC_SET_PWMTHRS(Z,Z3));
  288. TERN_(Z4_HAS_STEALTHCHOP, if (!index || index == 4) TMC_SET_PWMTHRS(Z,Z4));
  289. break;
  290. #endif
  291. #if I_HAS_STEALTHCHOP
  292. case I_AXIS: TMC_SET_PWMTHRS(I,I); break;
  293. #endif
  294. #if J_HAS_STEALTHCHOP
  295. case J_AXIS: TMC_SET_PWMTHRS(J,J); break;
  296. #endif
  297. #if K_HAS_STEALTHCHOP
  298. case K_AXIS: TMC_SET_PWMTHRS(K,K); break;
  299. #endif
  300. #if U_HAS_STEALTHCHOP
  301. case U_AXIS: TMC_SET_PWMTHRS(U,U); break;
  302. #endif
  303. #if V_HAS_STEALTHCHOP
  304. case V_AXIS: TMC_SET_PWMTHRS(V,V); break;
  305. #endif
  306. #if W_HAS_STEALTHCHOP
  307. case W_AXIS: TMC_SET_PWMTHRS(W,W); break;
  308. #endif
  309. #if E0_HAS_STEALTHCHOP || E1_HAS_STEALTHCHOP || E2_HAS_STEALTHCHOP || E3_HAS_STEALTHCHOP || E4_HAS_STEALTHCHOP || E5_HAS_STEALTHCHOP || E6_HAS_STEALTHCHOP || E7_HAS_STEALTHCHOP
  310. case E_AXIS: {
  311. const int8_t eindex = get_target_e_stepper_from_command(-2);
  312. TERN_(E0_HAS_STEALTHCHOP, if (eindex < 0 || eindex == 0) TMC_SET_PWMTHRS_E(0));
  313. TERN_(E1_HAS_STEALTHCHOP, if (eindex < 0 || eindex == 1) TMC_SET_PWMTHRS_E(1));
  314. TERN_(E2_HAS_STEALTHCHOP, if (eindex < 0 || eindex == 2) TMC_SET_PWMTHRS_E(2));
  315. TERN_(E3_HAS_STEALTHCHOP, if (eindex < 0 || eindex == 3) TMC_SET_PWMTHRS_E(3));
  316. TERN_(E4_HAS_STEALTHCHOP, if (eindex < 0 || eindex == 4) TMC_SET_PWMTHRS_E(4));
  317. TERN_(E5_HAS_STEALTHCHOP, if (eindex < 0 || eindex == 5) TMC_SET_PWMTHRS_E(5));
  318. TERN_(E6_HAS_STEALTHCHOP, if (eindex < 0 || eindex == 6) TMC_SET_PWMTHRS_E(6));
  319. TERN_(E7_HAS_STEALTHCHOP, if (eindex < 0 || eindex == 7) TMC_SET_PWMTHRS_E(7));
  320. } break;
  321. #endif // E_STEPPERS
  322. }
  323. }
  324. if (report) {
  325. TERN_( X_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(X,X));
  326. TERN_(X2_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(X,X2));
  327. TERN_( Y_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(Y,Y));
  328. TERN_(Y2_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(Y,Y2));
  329. TERN_( Z_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(Z,Z));
  330. TERN_(Z2_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(Z,Z2));
  331. TERN_(Z3_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(Z,Z3));
  332. TERN_(Z4_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(Z,Z4));
  333. TERN_( I_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(I,I));
  334. TERN_( J_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(J,J));
  335. TERN_( K_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(K,K));
  336. TERN_( U_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(U,U));
  337. TERN_( V_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(V,V));
  338. TERN_( W_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(W,W));
  339. TERN_(E0_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS_E(0));
  340. TERN_(E1_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS_E(1));
  341. TERN_(E2_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS_E(2));
  342. TERN_(E3_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS_E(3));
  343. TERN_(E4_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS_E(4));
  344. TERN_(E5_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS_E(5));
  345. TERN_(E6_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS_E(6));
  346. TERN_(E7_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS_E(7));
  347. }
  348. }
  349. void GcodeSuite::M913_report(const bool forReplay/*=true*/) {
  350. report_heading(forReplay, F(STR_HYBRID_THRESHOLD));
  351. auto say_M913 = [](const bool forReplay) {
  352. report_echo_start(forReplay);
  353. SERIAL_ECHOPGM(" M913");
  354. };
  355. #if X_HAS_STEALTHCHOP || Y_HAS_STEALTHCHOP || Z_HAS_STEALTHCHOP
  356. say_M913(forReplay);
  357. #if X_HAS_STEALTHCHOP
  358. SERIAL_ECHOPGM_P(SP_X_STR, stepperX.get_pwm_thrs());
  359. #endif
  360. #if Y_HAS_STEALTHCHOP
  361. SERIAL_ECHOPGM_P(SP_Y_STR, stepperY.get_pwm_thrs());
  362. #endif
  363. #if Z_HAS_STEALTHCHOP
  364. SERIAL_ECHOPGM_P(SP_Z_STR, stepperZ.get_pwm_thrs());
  365. #endif
  366. SERIAL_EOL();
  367. #endif
  368. #if X2_HAS_STEALTHCHOP || Y2_HAS_STEALTHCHOP || Z2_HAS_STEALTHCHOP
  369. say_M913(forReplay);
  370. SERIAL_ECHOPGM(" I2");
  371. #if X2_HAS_STEALTHCHOP
  372. SERIAL_ECHOPGM_P(SP_X_STR, stepperX2.get_pwm_thrs());
  373. #endif
  374. #if Y2_HAS_STEALTHCHOP
  375. SERIAL_ECHOPGM_P(SP_Y_STR, stepperY2.get_pwm_thrs());
  376. #endif
  377. #if Z2_HAS_STEALTHCHOP
  378. SERIAL_ECHOPGM_P(SP_Z_STR, stepperZ2.get_pwm_thrs());
  379. #endif
  380. SERIAL_EOL();
  381. #endif
  382. #if Z3_HAS_STEALTHCHOP
  383. say_M913(forReplay);
  384. SERIAL_ECHOLNPGM(" I3 Z", stepperZ3.get_pwm_thrs());
  385. #endif
  386. #if Z4_HAS_STEALTHCHOP
  387. say_M913(forReplay);
  388. SERIAL_ECHOLNPGM(" I4 Z", stepperZ4.get_pwm_thrs());
  389. #endif
  390. #if I_HAS_STEALTHCHOP
  391. say_M913(forReplay);
  392. SERIAL_ECHOLNPGM_P(SP_I_STR, stepperI.get_pwm_thrs());
  393. #endif
  394. #if J_HAS_STEALTHCHOP
  395. say_M913(forReplay);
  396. SERIAL_ECHOLNPGM_P(SP_J_STR, stepperJ.get_pwm_thrs());
  397. #endif
  398. #if K_HAS_STEALTHCHOP
  399. say_M913(forReplay);
  400. SERIAL_ECHOLNPGM_P(SP_K_STR, stepperK.get_pwm_thrs());
  401. #endif
  402. #if U_HAS_STEALTHCHOP
  403. say_M913(forReplay);
  404. SERIAL_ECHOLNPGM_P(SP_U_STR, stepperU.get_pwm_thrs());
  405. #endif
  406. #if V_HAS_STEALTHCHOP
  407. say_M913(forReplay);
  408. SERIAL_ECHOLNPGM_P(SP_V_STR, stepperV.get_pwm_thrs());
  409. #endif
  410. #if W_HAS_STEALTHCHOP
  411. say_M913(forReplay);
  412. SERIAL_ECHOLNPGM_P(SP_W_STR, stepperW.get_pwm_thrs());
  413. #endif
  414. #if E0_HAS_STEALTHCHOP
  415. say_M913(forReplay);
  416. SERIAL_ECHOLNPGM(" T0 E", stepperE0.get_pwm_thrs());
  417. #endif
  418. #if E1_HAS_STEALTHCHOP
  419. say_M913(forReplay);
  420. SERIAL_ECHOLNPGM(" T1 E", stepperE1.get_pwm_thrs());
  421. #endif
  422. #if E2_HAS_STEALTHCHOP
  423. say_M913(forReplay);
  424. SERIAL_ECHOLNPGM(" T2 E", stepperE2.get_pwm_thrs());
  425. #endif
  426. #if E3_HAS_STEALTHCHOP
  427. say_M913(forReplay);
  428. SERIAL_ECHOLNPGM(" T3 E", stepperE3.get_pwm_thrs());
  429. #endif
  430. #if E4_HAS_STEALTHCHOP
  431. say_M913(forReplay);
  432. SERIAL_ECHOLNPGM(" T4 E", stepperE4.get_pwm_thrs());
  433. #endif
  434. #if E5_HAS_STEALTHCHOP
  435. say_M913(forReplay);
  436. SERIAL_ECHOLNPGM(" T5 E", stepperE5.get_pwm_thrs());
  437. #endif
  438. #if E6_HAS_STEALTHCHOP
  439. say_M913(forReplay);
  440. SERIAL_ECHOLNPGM(" T6 E", stepperE6.get_pwm_thrs());
  441. #endif
  442. #if E7_HAS_STEALTHCHOP
  443. say_M913(forReplay);
  444. SERIAL_ECHOLNPGM(" T7 E", stepperE7.get_pwm_thrs());
  445. #endif
  446. SERIAL_EOL();
  447. }
  448. #endif // HYBRID_THRESHOLD
  449. #if USE_SENSORLESS
  450. template<typename TMC>
  451. static void tmc_print_sgt(TMC &st) {
  452. st.printLabel();
  453. SERIAL_ECHOPGM(" homing sensitivity: ");
  454. SERIAL_PRINTLN(st.homing_threshold(), PrintBase::Dec);
  455. }
  456. /**
  457. * M914: Set StallGuard sensitivity.
  458. */
  459. void GcodeSuite::M914() {
  460. bool report = true;
  461. const uint8_t index = parser.byteval('I');
  462. LOOP_NUM_AXES(i) if (parser.seen(AXIS_CHAR(i))) {
  463. const int16_t value = parser.value_int();
  464. report = false;
  465. switch (i) {
  466. #if X_SENSORLESS
  467. case X_AXIS:
  468. if (index < 2) stepperX.homing_threshold(value);
  469. TERN_(X2_SENSORLESS, if (!index || index == 2) stepperX2.homing_threshold(value));
  470. break;
  471. #endif
  472. #if Y_SENSORLESS
  473. case Y_AXIS:
  474. if (index < 2) stepperY.homing_threshold(value);
  475. TERN_(Y2_SENSORLESS, if (!index || index == 2) stepperY2.homing_threshold(value));
  476. break;
  477. #endif
  478. #if Z_SENSORLESS
  479. case Z_AXIS:
  480. if (index < 2) stepperZ.homing_threshold(value);
  481. TERN_(Z2_SENSORLESS, if (!index || index == 2) stepperZ2.homing_threshold(value));
  482. TERN_(Z3_SENSORLESS, if (!index || index == 3) stepperZ3.homing_threshold(value));
  483. TERN_(Z4_SENSORLESS, if (!index || index == 4) stepperZ4.homing_threshold(value));
  484. break;
  485. #endif
  486. #if I_SENSORLESS
  487. case I_AXIS: stepperI.homing_threshold(value); break;
  488. #endif
  489. #if J_SENSORLESS
  490. case J_AXIS: stepperJ.homing_threshold(value); break;
  491. #endif
  492. #if K_SENSORLESS
  493. case K_AXIS: stepperK.homing_threshold(value); break;
  494. #endif
  495. #if U_SENSORLESS && AXIS_HAS_STALLGUARD(U)
  496. case U_AXIS: stepperU.homing_threshold(value); break;
  497. #endif
  498. #if V_SENSORLESS && AXIS_HAS_STALLGUARD(V)
  499. case V_AXIS: stepperV.homing_threshold(value); break;
  500. #endif
  501. #if W_SENSORLESS && AXIS_HAS_STALLGUARD(W)
  502. case W_AXIS: stepperW.homing_threshold(value); break;
  503. #endif
  504. }
  505. }
  506. if (report) {
  507. TERN_(X_SENSORLESS, tmc_print_sgt(stepperX));
  508. TERN_(X2_SENSORLESS, tmc_print_sgt(stepperX2));
  509. TERN_(Y_SENSORLESS, tmc_print_sgt(stepperY));
  510. TERN_(Y2_SENSORLESS, tmc_print_sgt(stepperY2));
  511. TERN_(Z_SENSORLESS, tmc_print_sgt(stepperZ));
  512. TERN_(Z2_SENSORLESS, tmc_print_sgt(stepperZ2));
  513. TERN_(Z3_SENSORLESS, tmc_print_sgt(stepperZ3));
  514. TERN_(Z4_SENSORLESS, tmc_print_sgt(stepperZ4));
  515. TERN_(I_SENSORLESS, tmc_print_sgt(stepperI));
  516. TERN_(J_SENSORLESS, tmc_print_sgt(stepperJ));
  517. TERN_(K_SENSORLESS, tmc_print_sgt(stepperK));
  518. TERN_(U_SENSORLESS, tmc_print_sgt(stepperU));
  519. TERN_(V_SENSORLESS, tmc_print_sgt(stepperV));
  520. TERN_(W_SENSORLESS, tmc_print_sgt(stepperW));
  521. }
  522. }
  523. void GcodeSuite::M914_report(const bool forReplay/*=true*/) {
  524. report_heading(forReplay, F(STR_STALLGUARD_THRESHOLD));
  525. auto say_M914 = [](const bool forReplay) {
  526. report_echo_start(forReplay);
  527. SERIAL_ECHOPGM(" M914");
  528. };
  529. #if X_SENSORLESS || Y_SENSORLESS || Z_SENSORLESS
  530. say_M914(forReplay);
  531. #if X_SENSORLESS
  532. SERIAL_ECHOPGM_P(SP_X_STR, stepperX.homing_threshold());
  533. #endif
  534. #if Y_SENSORLESS
  535. SERIAL_ECHOPGM_P(SP_Y_STR, stepperY.homing_threshold());
  536. #endif
  537. #if Z_SENSORLESS
  538. SERIAL_ECHOPGM_P(SP_Z_STR, stepperZ.homing_threshold());
  539. #endif
  540. SERIAL_EOL();
  541. #endif
  542. #if X2_SENSORLESS || Y2_SENSORLESS || Z2_SENSORLESS
  543. say_M914(forReplay);
  544. SERIAL_ECHOPGM(" I2");
  545. #if X2_SENSORLESS
  546. SERIAL_ECHOPGM_P(SP_X_STR, stepperX2.homing_threshold());
  547. #endif
  548. #if Y2_SENSORLESS
  549. SERIAL_ECHOPGM_P(SP_Y_STR, stepperY2.homing_threshold());
  550. #endif
  551. #if Z2_SENSORLESS
  552. SERIAL_ECHOPGM_P(SP_Z_STR, stepperZ2.homing_threshold());
  553. #endif
  554. SERIAL_EOL();
  555. #endif
  556. #if Z3_SENSORLESS
  557. say_M914(forReplay);
  558. SERIAL_ECHOLNPGM(" I3 Z", stepperZ3.homing_threshold());
  559. #endif
  560. #if Z4_SENSORLESS
  561. say_M914(forReplay);
  562. SERIAL_ECHOLNPGM(" I4 Z", stepperZ4.homing_threshold());
  563. #endif
  564. #if I_SENSORLESS
  565. say_M914(forReplay);
  566. SERIAL_ECHOLNPGM_P(SP_I_STR, stepperI.homing_threshold());
  567. #endif
  568. #if J_SENSORLESS
  569. say_M914(forReplay);
  570. SERIAL_ECHOLNPGM_P(SP_J_STR, stepperJ.homing_threshold());
  571. #endif
  572. #if K_SENSORLESS
  573. say_M914(forReplay);
  574. SERIAL_ECHOLNPGM_P(SP_K_STR, stepperK.homing_threshold());
  575. #endif
  576. #if U_SENSORLESS
  577. say_M914(forReplay);
  578. SERIAL_ECHOLNPGM_P(SP_U_STR, stepperU.homing_threshold());
  579. #endif
  580. #if V_SENSORLESS
  581. say_M914(forReplay);
  582. SERIAL_ECHOLNPGM_P(SP_V_STR, stepperV.homing_threshold());
  583. #endif
  584. #if W_SENSORLESS
  585. say_M914(forReplay);
  586. SERIAL_ECHOLNPGM_P(SP_W_STR, stepperW.homing_threshold());
  587. #endif
  588. }
  589. #endif // USE_SENSORLESS
  590. #endif // HAS_TRINAMIC_CONFIG