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.

trinamic.cpp 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933
  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. /**
  23. * stepper/trinamic.cpp
  24. * Stepper driver indirection for Trinamic
  25. */
  26. #include "../../inc/MarlinConfig.h"
  27. #if HAS_TRINAMIC_CONFIG
  28. #include "trinamic.h"
  29. #include "../stepper.h"
  30. #include <HardwareSerial.h>
  31. #include <SPI.h>
  32. enum StealthIndex : uint8_t {
  33. LOGICAL_AXIS_LIST(STEALTH_AXIS_E, STEALTH_AXIS_X, STEALTH_AXIS_Y, STEALTH_AXIS_Z)
  34. };
  35. #define TMC_INIT(ST, STEALTH_INDEX) tmc_init(stepper##ST, ST##_CURRENT, ST##_MICROSTEPS, ST##_HYBRID_THRESHOLD, stealthchop_by_axis[STEALTH_INDEX], chopper_timing_##ST, ST##_INTERPOLATE)
  36. // IC = TMC model number
  37. // ST = Stepper object letter
  38. // L = Label characters
  39. // AI = Axis Enum Index
  40. // SWHW = SW/SH UART selection
  41. #if ENABLED(TMC_USE_SW_SPI)
  42. #define __TMC_SPI_DEFINE(IC, ST, L, AI) TMCMarlin<IC##Stepper, L, AI> stepper##ST(ST##_CS_PIN, float(ST##_RSENSE), TMC_SW_MOSI, TMC_SW_MISO, TMC_SW_SCK, ST##_CHAIN_POS)
  43. #else
  44. #define __TMC_SPI_DEFINE(IC, ST, L, AI) TMCMarlin<IC##Stepper, L, AI> stepper##ST(ST##_CS_PIN, float(ST##_RSENSE), ST##_CHAIN_POS)
  45. #endif
  46. #if ENABLED(TMC_SERIAL_MULTIPLEXER)
  47. #define TMC_UART_HW_DEFINE(IC, ST, L, AI) TMCMarlin<IC##Stepper, L, AI> stepper##ST(&ST##_HARDWARE_SERIAL, float(ST##_RSENSE), ST##_SLAVE_ADDRESS, SERIAL_MUL_PIN1, SERIAL_MUL_PIN2)
  48. #else
  49. #define TMC_UART_HW_DEFINE(IC, ST, L, AI) TMCMarlin<IC##Stepper, L, AI> stepper##ST(&ST##_HARDWARE_SERIAL, float(ST##_RSENSE), ST##_SLAVE_ADDRESS)
  50. #endif
  51. #define TMC_UART_SW_DEFINE(IC, ST, L, AI) TMCMarlin<IC##Stepper, L, AI> stepper##ST(ST##_SERIAL_RX_PIN, ST##_SERIAL_TX_PIN, float(ST##_RSENSE), ST##_SLAVE_ADDRESS)
  52. #define _TMC_SPI_DEFINE(IC, ST, AI) __TMC_SPI_DEFINE(IC, ST, TMC_##ST##_LABEL, AI)
  53. #define TMC_SPI_DEFINE(ST, AI) _TMC_SPI_DEFINE(ST##_DRIVER_TYPE, ST, AI##_AXIS)
  54. #define _TMC_UART_DEFINE(SWHW, IC, ST, AI) TMC_UART_##SWHW##_DEFINE(IC, ST, TMC_##ST##_LABEL, AI)
  55. #define TMC_UART_DEFINE(SWHW, ST, AI) _TMC_UART_DEFINE(SWHW, ST##_DRIVER_TYPE, ST, AI##_AXIS)
  56. #if ENABLED(DISTINCT_E_FACTORS)
  57. #define TMC_SPI_DEFINE_E(AI) TMC_SPI_DEFINE(E##AI, E##AI)
  58. #define TMC_UART_DEFINE_E(SWHW, AI) TMC_UART_DEFINE(SWHW, E##AI, E##AI)
  59. #else
  60. #define TMC_SPI_DEFINE_E(AI) TMC_SPI_DEFINE(E##AI, E)
  61. #define TMC_UART_DEFINE_E(SWHW, AI) TMC_UART_DEFINE(SWHW, E##AI, E)
  62. #endif
  63. // Stepper objects of TMC2130/TMC2160/TMC2660/TMC5130/TMC5160 steppers used
  64. #if AXIS_HAS_SPI(X)
  65. TMC_SPI_DEFINE(X, X);
  66. #endif
  67. #if AXIS_HAS_SPI(X2)
  68. TMC_SPI_DEFINE(X2, X);
  69. #endif
  70. #if AXIS_HAS_SPI(Y)
  71. TMC_SPI_DEFINE(Y, Y);
  72. #endif
  73. #if AXIS_HAS_SPI(Y2)
  74. TMC_SPI_DEFINE(Y2, Y);
  75. #endif
  76. #if AXIS_HAS_SPI(Z)
  77. TMC_SPI_DEFINE(Z, Z);
  78. #endif
  79. #if AXIS_HAS_SPI(Z2)
  80. TMC_SPI_DEFINE(Z2, Z);
  81. #endif
  82. #if AXIS_HAS_SPI(Z3)
  83. TMC_SPI_DEFINE(Z3, Z);
  84. #endif
  85. #if AXIS_HAS_SPI(Z4)
  86. TMC_SPI_DEFINE(Z4, Z);
  87. #endif
  88. #if AXIS_HAS_SPI(E0)
  89. TMC_SPI_DEFINE_E(0);
  90. #endif
  91. #if AXIS_HAS_SPI(E1)
  92. TMC_SPI_DEFINE_E(1);
  93. #endif
  94. #if AXIS_HAS_SPI(E2)
  95. TMC_SPI_DEFINE_E(2);
  96. #endif
  97. #if AXIS_HAS_SPI(E3)
  98. TMC_SPI_DEFINE_E(3);
  99. #endif
  100. #if AXIS_HAS_SPI(E4)
  101. TMC_SPI_DEFINE_E(4);
  102. #endif
  103. #if AXIS_HAS_SPI(E5)
  104. TMC_SPI_DEFINE_E(5);
  105. #endif
  106. #if AXIS_HAS_SPI(E6)
  107. TMC_SPI_DEFINE_E(6);
  108. #endif
  109. #if AXIS_HAS_SPI(E7)
  110. TMC_SPI_DEFINE_E(7);
  111. #endif
  112. #ifndef TMC_BAUD_RATE
  113. // Reduce baud rate for boards not already overriding TMC_BAUD_RATE for software serial.
  114. // Testing has shown that 115200 is not 100% reliable on AVR platforms, occasionally
  115. // failing to read status properly. 32-bit platforms typically define an even lower
  116. // TMC_BAUD_RATE, due to differences in how SoftwareSerial libraries work on different
  117. // platforms.
  118. #define TMC_BAUD_RATE TERN(HAS_TMC_SW_SERIAL, 57600, 115200)
  119. #endif
  120. #ifndef TMC_X_BAUD_RATE
  121. #define TMC_X_BAUD_RATE TMC_BAUD_RATE
  122. #endif
  123. #ifndef TMC_X2_BAUD_RATE
  124. #define TMC_X2_BAUD_RATE TMC_BAUD_RATE
  125. #endif
  126. #ifndef TMC_Y_BAUD_RATE
  127. #define TMC_Y_BAUD_RATE TMC_BAUD_RATE
  128. #endif
  129. #ifndef TMC_Y2_BAUD_RATE
  130. #define TMC_Y2_BAUD_RATE TMC_BAUD_RATE
  131. #endif
  132. #ifndef TMC_Z_BAUD_RATE
  133. #define TMC_Z_BAUD_RATE TMC_BAUD_RATE
  134. #endif
  135. #ifndef TMC_Z2_BAUD_RATE
  136. #define TMC_Z2_BAUD_RATE TMC_BAUD_RATE
  137. #endif
  138. #ifndef TMC_Z3_BAUD_RATE
  139. #define TMC_Z3_BAUD_RATE TMC_BAUD_RATE
  140. #endif
  141. #ifndef TMC_Z4_BAUD_RATE
  142. #define TMC_Z4_BAUD_RATE TMC_BAUD_RATE
  143. #endif
  144. #ifndef TMC_E0_BAUD_RATE
  145. #define TMC_E0_BAUD_RATE TMC_BAUD_RATE
  146. #endif
  147. #ifndef TMC_E1_BAUD_RATE
  148. #define TMC_E1_BAUD_RATE TMC_BAUD_RATE
  149. #endif
  150. #ifndef TMC_E2_BAUD_RATE
  151. #define TMC_E2_BAUD_RATE TMC_BAUD_RATE
  152. #endif
  153. #ifndef TMC_E3_BAUD_RATE
  154. #define TMC_E3_BAUD_RATE TMC_BAUD_RATE
  155. #endif
  156. #ifndef TMC_E4_BAUD_RATE
  157. #define TMC_E4_BAUD_RATE TMC_BAUD_RATE
  158. #endif
  159. #ifndef TMC_E5_BAUD_RATE
  160. #define TMC_E5_BAUD_RATE TMC_BAUD_RATE
  161. #endif
  162. #ifndef TMC_E6_BAUD_RATE
  163. #define TMC_E6_BAUD_RATE TMC_BAUD_RATE
  164. #endif
  165. #ifndef TMC_E7_BAUD_RATE
  166. #define TMC_E7_BAUD_RATE TMC_BAUD_RATE
  167. #endif
  168. #if HAS_DRIVER(TMC2130)
  169. template<char AXIS_LETTER, char DRIVER_ID, AxisEnum AXIS_ID>
  170. void tmc_init(TMCMarlin<TMC2130Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate) {
  171. st.begin();
  172. CHOPCONF_t chopconf{0};
  173. chopconf.tbl = 0b01;
  174. chopconf.toff = chop_init.toff;
  175. chopconf.intpol = interpolate;
  176. chopconf.hend = chop_init.hend + 3;
  177. chopconf.hstrt = chop_init.hstrt - 1;
  178. TERN_(SQUARE_WAVE_STEPPING, chopconf.dedge = true);
  179. st.CHOPCONF(chopconf.sr);
  180. st.rms_current(mA, HOLD_MULTIPLIER);
  181. st.microsteps(microsteps);
  182. st.iholddelay(10);
  183. st.TPOWERDOWN(128); // ~2s until driver lowers to hold current
  184. st.en_pwm_mode(stealth);
  185. st.stored.stealthChop_enabled = stealth;
  186. PWMCONF_t pwmconf{0};
  187. pwmconf.pwm_freq = 0b01; // f_pwm = 2/683 f_clk
  188. pwmconf.pwm_autoscale = true;
  189. pwmconf.pwm_grad = 5;
  190. pwmconf.pwm_ampl = 180;
  191. st.PWMCONF(pwmconf.sr);
  192. TERN(HYBRID_THRESHOLD, st.set_pwm_thrs(hyb_thrs), UNUSED(hyb_thrs));
  193. st.GSTAT(); // Clear GSTAT
  194. }
  195. #endif // TMC2130
  196. #if HAS_DRIVER(TMC2160)
  197. template<char AXIS_LETTER, char DRIVER_ID, AxisEnum AXIS_ID>
  198. void tmc_init(TMCMarlin<TMC2160Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate) {
  199. st.begin();
  200. CHOPCONF_t chopconf{0};
  201. chopconf.tbl = 0b01;
  202. chopconf.toff = chop_init.toff;
  203. chopconf.intpol = interpolate;
  204. chopconf.hend = chop_init.hend + 3;
  205. chopconf.hstrt = chop_init.hstrt - 1;
  206. TERN_(SQUARE_WAVE_STEPPING, chopconf.dedge = true);
  207. st.CHOPCONF(chopconf.sr);
  208. st.rms_current(mA, HOLD_MULTIPLIER);
  209. st.microsteps(microsteps);
  210. st.iholddelay(10);
  211. st.TPOWERDOWN(128); // ~2s until driver lowers to hold current
  212. st.en_pwm_mode(stealth);
  213. st.stored.stealthChop_enabled = stealth;
  214. TMC2160_n::PWMCONF_t pwmconf{0};
  215. pwmconf.pwm_lim = 12;
  216. pwmconf.pwm_reg = 8;
  217. pwmconf.pwm_autograd = true;
  218. pwmconf.pwm_autoscale = true;
  219. pwmconf.pwm_freq = 0b01;
  220. pwmconf.pwm_grad = 14;
  221. pwmconf.pwm_ofs = 36;
  222. st.PWMCONF(pwmconf.sr);
  223. TERN(HYBRID_THRESHOLD, st.set_pwm_thrs(hyb_thrs), UNUSED(hyb_thrs));
  224. st.GSTAT(); // Clear GSTAT
  225. }
  226. #endif // TMC2160
  227. //
  228. // TMC2208/2209 Driver objects and inits
  229. //
  230. #if HAS_TMC220x
  231. #if AXIS_HAS_UART(X)
  232. #ifdef X_HARDWARE_SERIAL
  233. TMC_UART_DEFINE(HW, X, X);
  234. #define X_HAS_HW_SERIAL 1
  235. #else
  236. TMC_UART_DEFINE(SW, X, X);
  237. #define X_HAS_SW_SERIAL 1
  238. #endif
  239. #endif
  240. #if AXIS_HAS_UART(X2)
  241. #ifdef X2_HARDWARE_SERIAL
  242. TMC_UART_DEFINE(HW, X2, X);
  243. #define X2_HAS_HW_SERIAL 1
  244. #else
  245. TMC_UART_DEFINE(SW, X2, X);
  246. #define X2_HAS_SW_SERIAL 1
  247. #endif
  248. #endif
  249. #if AXIS_HAS_UART(Y)
  250. #ifdef Y_HARDWARE_SERIAL
  251. TMC_UART_DEFINE(HW, Y, Y);
  252. #define Y_HAS_HW_SERIAL 1
  253. #else
  254. TMC_UART_DEFINE(SW, Y, Y);
  255. #define Y_HAS_SW_SERIAL 1
  256. #endif
  257. #endif
  258. #if AXIS_HAS_UART(Y2)
  259. #ifdef Y2_HARDWARE_SERIAL
  260. TMC_UART_DEFINE(HW, Y2, Y);
  261. #define Y2_HAS_HW_SERIAL 1
  262. #else
  263. TMC_UART_DEFINE(SW, Y2, Y);
  264. #define Y2_HAS_SW_SERIAL 1
  265. #endif
  266. #endif
  267. #if AXIS_HAS_UART(Z)
  268. #ifdef Z_HARDWARE_SERIAL
  269. TMC_UART_DEFINE(HW, Z, Z);
  270. #define Z_HAS_HW_SERIAL 1
  271. #else
  272. TMC_UART_DEFINE(SW, Z, Z);
  273. #define Z_HAS_SW_SERIAL 1
  274. #endif
  275. #endif
  276. #if AXIS_HAS_UART(Z2)
  277. #ifdef Z2_HARDWARE_SERIAL
  278. TMC_UART_DEFINE(HW, Z2, Z);
  279. #define Z2_HAS_HW_SERIAL 1
  280. #else
  281. TMC_UART_DEFINE(SW, Z2, Z);
  282. #define Z2_HAS_SW_SERIAL 1
  283. #endif
  284. #endif
  285. #if AXIS_HAS_UART(Z3)
  286. #ifdef Z3_HARDWARE_SERIAL
  287. TMC_UART_DEFINE(HW, Z3, Z);
  288. #define Z3_HAS_HW_SERIAL 1
  289. #else
  290. TMC_UART_DEFINE(SW, Z3, Z);
  291. #define Z3_HAS_SW_SERIAL 1
  292. #endif
  293. #endif
  294. #if AXIS_HAS_UART(Z4)
  295. #ifdef Z4_HARDWARE_SERIAL
  296. TMC_UART_DEFINE(HW, Z4, Z);
  297. #define Z4_HAS_HW_SERIAL 1
  298. #else
  299. TMC_UART_DEFINE(SW, Z4, Z);
  300. #define Z4_HAS_SW_SERIAL 1
  301. #endif
  302. #endif
  303. #if AXIS_HAS_UART(E0)
  304. #ifdef E0_HARDWARE_SERIAL
  305. TMC_UART_DEFINE_E(HW, 0);
  306. #define E0_HAS_HW_SERIAL 1
  307. #else
  308. TMC_UART_DEFINE_E(SW, 0);
  309. #define E0_HAS_SW_SERIAL 1
  310. #endif
  311. #endif
  312. #if AXIS_HAS_UART(E1)
  313. #ifdef E1_HARDWARE_SERIAL
  314. TMC_UART_DEFINE_E(HW, 1);
  315. #define E1_HAS_HW_SERIAL 1
  316. #else
  317. TMC_UART_DEFINE_E(SW, 1);
  318. #define E1_HAS_SW_SERIAL 1
  319. #endif
  320. #endif
  321. #if AXIS_HAS_UART(E2)
  322. #ifdef E2_HARDWARE_SERIAL
  323. TMC_UART_DEFINE_E(HW, 2);
  324. #define E2_HAS_HW_SERIAL 1
  325. #else
  326. TMC_UART_DEFINE_E(SW, 2);
  327. #define E2_HAS_SW_SERIAL 1
  328. #endif
  329. #endif
  330. #if AXIS_HAS_UART(E3)
  331. #ifdef E3_HARDWARE_SERIAL
  332. TMC_UART_DEFINE_E(HW, 3);
  333. #define E3_HAS_HW_SERIAL 1
  334. #else
  335. TMC_UART_DEFINE_E(SW, 3);
  336. #define E3_HAS_SW_SERIAL 1
  337. #endif
  338. #endif
  339. #if AXIS_HAS_UART(E4)
  340. #ifdef E4_HARDWARE_SERIAL
  341. TMC_UART_DEFINE_E(HW, 4);
  342. #define E4_HAS_HW_SERIAL 1
  343. #else
  344. TMC_UART_DEFINE_E(SW, 4);
  345. #define E4_HAS_SW_SERIAL 1
  346. #endif
  347. #endif
  348. #if AXIS_HAS_UART(E5)
  349. #ifdef E5_HARDWARE_SERIAL
  350. TMC_UART_DEFINE_E(HW, 5);
  351. #define E5_HAS_HW_SERIAL 1
  352. #else
  353. TMC_UART_DEFINE_E(SW, 5);
  354. #define E5_HAS_SW_SERIAL 1
  355. #endif
  356. #endif
  357. #if AXIS_HAS_UART(E6)
  358. #ifdef E6_HARDWARE_SERIAL
  359. TMC_UART_DEFINE_E(HW, 6);
  360. #define E6_HAS_HW_SERIAL 1
  361. #else
  362. TMC_UART_DEFINE_E(SW, 6);
  363. #define E6_HAS_SW_SERIAL 1
  364. #endif
  365. #endif
  366. #if AXIS_HAS_UART(E7)
  367. #ifdef E7_HARDWARE_SERIAL
  368. TMC_UART_DEFINE_E(HW, 7);
  369. #define E7_HAS_HW_SERIAL 1
  370. #else
  371. TMC_UART_DEFINE_E(SW, 7);
  372. #define E7_HAS_SW_SERIAL 1
  373. #endif
  374. #endif
  375. enum TMCAxis : uint8_t { LINEAR_AXIS_LIST(X, Y, Z), X2, Y2, Z2, Z3, Z4, E0, E1, E2, E3, E4, E5, E6, E7, TOTAL };
  376. void tmc_serial_begin() {
  377. #if HAS_TMC_HW_SERIAL
  378. struct {
  379. const void *ptr[TMCAxis::TOTAL];
  380. bool began(const TMCAxis a, const void * const p) {
  381. LOOP_L_N(i, a) if (p == ptr[i]) return true;
  382. ptr[a] = p; return false;
  383. };
  384. } sp_helper;
  385. #define HW_SERIAL_BEGIN(A) do{ if (!sp_helper.began(TMCAxis::A, &A##_HARDWARE_SERIAL)) \
  386. A##_HARDWARE_SERIAL.begin(TMC_##A##_BAUD_RATE); }while(0)
  387. #endif
  388. #if AXIS_HAS_UART(X)
  389. #ifdef X_HARDWARE_SERIAL
  390. HW_SERIAL_BEGIN(X);
  391. #else
  392. stepperX.beginSerial(TMC_BAUD_RATE);
  393. #endif
  394. #endif
  395. #if AXIS_HAS_UART(X2)
  396. #ifdef X2_HARDWARE_SERIAL
  397. HW_SERIAL_BEGIN(X2);
  398. #else
  399. stepperX2.beginSerial(TMC_BAUD_RATE);
  400. #endif
  401. #endif
  402. #if AXIS_HAS_UART(Y)
  403. #ifdef Y_HARDWARE_SERIAL
  404. HW_SERIAL_BEGIN(Y);
  405. #else
  406. stepperY.beginSerial(TMC_BAUD_RATE);
  407. #endif
  408. #endif
  409. #if AXIS_HAS_UART(Y2)
  410. #ifdef Y2_HARDWARE_SERIAL
  411. HW_SERIAL_BEGIN(Y2);
  412. #else
  413. stepperY2.beginSerial(TMC_BAUD_RATE);
  414. #endif
  415. #endif
  416. #if AXIS_HAS_UART(Z)
  417. #ifdef Z_HARDWARE_SERIAL
  418. HW_SERIAL_BEGIN(Z);
  419. #else
  420. stepperZ.beginSerial(TMC_BAUD_RATE);
  421. #endif
  422. #endif
  423. #if AXIS_HAS_UART(Z2)
  424. #ifdef Z2_HARDWARE_SERIAL
  425. HW_SERIAL_BEGIN(Z2);
  426. #else
  427. stepperZ2.beginSerial(TMC_BAUD_RATE);
  428. #endif
  429. #endif
  430. #if AXIS_HAS_UART(Z3)
  431. #ifdef Z3_HARDWARE_SERIAL
  432. HW_SERIAL_BEGIN(Z3);
  433. #else
  434. stepperZ3.beginSerial(TMC_BAUD_RATE);
  435. #endif
  436. #endif
  437. #if AXIS_HAS_UART(Z4)
  438. #ifdef Z4_HARDWARE_SERIAL
  439. HW_SERIAL_BEGIN(Z4);
  440. #else
  441. stepperZ4.beginSerial(TMC_BAUD_RATE);
  442. #endif
  443. #endif
  444. #if AXIS_HAS_UART(E0)
  445. #ifdef E0_HARDWARE_SERIAL
  446. HW_SERIAL_BEGIN(E0);
  447. #else
  448. stepperE0.beginSerial(TMC_BAUD_RATE);
  449. #endif
  450. #endif
  451. #if AXIS_HAS_UART(E1)
  452. #ifdef E1_HARDWARE_SERIAL
  453. HW_SERIAL_BEGIN(E1);
  454. #else
  455. stepperE1.beginSerial(TMC_BAUD_RATE);
  456. #endif
  457. #endif
  458. #if AXIS_HAS_UART(E2)
  459. #ifdef E2_HARDWARE_SERIAL
  460. HW_SERIAL_BEGIN(E2);
  461. #else
  462. stepperE2.beginSerial(TMC_BAUD_RATE);
  463. #endif
  464. #endif
  465. #if AXIS_HAS_UART(E3)
  466. #ifdef E3_HARDWARE_SERIAL
  467. HW_SERIAL_BEGIN(E3);
  468. #else
  469. stepperE3.beginSerial(TMC_BAUD_RATE);
  470. #endif
  471. #endif
  472. #if AXIS_HAS_UART(E4)
  473. #ifdef E4_HARDWARE_SERIAL
  474. HW_SERIAL_BEGIN(E4);
  475. #else
  476. stepperE4.beginSerial(TMC_BAUD_RATE);
  477. #endif
  478. #endif
  479. #if AXIS_HAS_UART(E5)
  480. #ifdef E5_HARDWARE_SERIAL
  481. HW_SERIAL_BEGIN(E5);
  482. #else
  483. stepperE5.beginSerial(TMC_BAUD_RATE);
  484. #endif
  485. #endif
  486. #if AXIS_HAS_UART(E6)
  487. #ifdef E6_HARDWARE_SERIAL
  488. HW_SERIAL_BEGIN(E6);
  489. #else
  490. stepperE6.beginSerial(TMC_BAUD_RATE);
  491. #endif
  492. #endif
  493. #if AXIS_HAS_UART(E7)
  494. #ifdef E7_HARDWARE_SERIAL
  495. HW_SERIAL_BEGIN(E7);
  496. #else
  497. stepperE7.beginSerial(TMC_BAUD_RATE);
  498. #endif
  499. #endif
  500. }
  501. #endif
  502. #if HAS_DRIVER(TMC2208)
  503. template<char AXIS_LETTER, char DRIVER_ID, AxisEnum AXIS_ID>
  504. void tmc_init(TMCMarlin<TMC2208Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate) {
  505. TMC2208_n::GCONF_t gconf{0};
  506. gconf.pdn_disable = true; // Use UART
  507. gconf.mstep_reg_select = true; // Select microsteps with UART
  508. gconf.i_scale_analog = false;
  509. gconf.en_spreadcycle = !stealth;
  510. st.GCONF(gconf.sr);
  511. st.stored.stealthChop_enabled = stealth;
  512. TMC2208_n::CHOPCONF_t chopconf{0};
  513. chopconf.tbl = 0b01; // blank_time = 24
  514. chopconf.toff = chop_init.toff;
  515. chopconf.intpol = interpolate;
  516. chopconf.hend = chop_init.hend + 3;
  517. chopconf.hstrt = chop_init.hstrt - 1;
  518. TERN_(SQUARE_WAVE_STEPPING, chopconf.dedge = true);
  519. st.CHOPCONF(chopconf.sr);
  520. st.rms_current(mA, HOLD_MULTIPLIER);
  521. st.microsteps(microsteps);
  522. st.iholddelay(10);
  523. st.TPOWERDOWN(128); // ~2s until driver lowers to hold current
  524. TMC2208_n::PWMCONF_t pwmconf{0};
  525. pwmconf.pwm_lim = 12;
  526. pwmconf.pwm_reg = 8;
  527. pwmconf.pwm_autograd = true;
  528. pwmconf.pwm_autoscale = true;
  529. pwmconf.pwm_freq = 0b01;
  530. pwmconf.pwm_grad = 14;
  531. pwmconf.pwm_ofs = 36;
  532. st.PWMCONF(pwmconf.sr);
  533. TERN(HYBRID_THRESHOLD, st.set_pwm_thrs(hyb_thrs), UNUSED(hyb_thrs));
  534. st.GSTAT(0b111); // Clear
  535. delay(200);
  536. }
  537. #endif // TMC2208
  538. #if HAS_DRIVER(TMC2209)
  539. template<char AXIS_LETTER, char DRIVER_ID, AxisEnum AXIS_ID>
  540. void tmc_init(TMCMarlin<TMC2209Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate) {
  541. TMC2208_n::GCONF_t gconf{0};
  542. gconf.pdn_disable = true; // Use UART
  543. gconf.mstep_reg_select = true; // Select microsteps with UART
  544. gconf.i_scale_analog = false;
  545. gconf.en_spreadcycle = !stealth;
  546. st.GCONF(gconf.sr);
  547. st.stored.stealthChop_enabled = stealth;
  548. TMC2208_n::CHOPCONF_t chopconf{0};
  549. chopconf.tbl = 0b01; // blank_time = 24
  550. chopconf.toff = chop_init.toff;
  551. chopconf.intpol = interpolate;
  552. chopconf.hend = chop_init.hend + 3;
  553. chopconf.hstrt = chop_init.hstrt - 1;
  554. TERN_(SQUARE_WAVE_STEPPING, chopconf.dedge = true);
  555. st.CHOPCONF(chopconf.sr);
  556. st.rms_current(mA, HOLD_MULTIPLIER);
  557. st.microsteps(microsteps);
  558. st.iholddelay(10);
  559. st.TPOWERDOWN(128); // ~2s until driver lowers to hold current
  560. TMC2208_n::PWMCONF_t pwmconf{0};
  561. pwmconf.pwm_lim = 12;
  562. pwmconf.pwm_reg = 8;
  563. pwmconf.pwm_autograd = true;
  564. pwmconf.pwm_autoscale = true;
  565. pwmconf.pwm_freq = 0b01;
  566. pwmconf.pwm_grad = 14;
  567. pwmconf.pwm_ofs = 36;
  568. st.PWMCONF(pwmconf.sr);
  569. TERN(HYBRID_THRESHOLD, st.set_pwm_thrs(hyb_thrs), UNUSED(hyb_thrs));
  570. st.GSTAT(0b111); // Clear
  571. delay(200);
  572. }
  573. #endif // TMC2209
  574. #if HAS_DRIVER(TMC2660)
  575. template<char AXIS_LETTER, char DRIVER_ID, AxisEnum AXIS_ID>
  576. void tmc_init(TMCMarlin<TMC2660Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t, const bool, const chopper_timing_t &chop_init, const bool interpolate) {
  577. st.begin();
  578. TMC2660_n::CHOPCONF_t chopconf{0};
  579. chopconf.tbl = 0b01;
  580. chopconf.toff = chop_init.toff;
  581. chopconf.hend = chop_init.hend + 3;
  582. chopconf.hstrt = chop_init.hstrt - 1;
  583. st.CHOPCONF(chopconf.sr);
  584. st.sdoff(0);
  585. st.rms_current(mA);
  586. st.microsteps(microsteps);
  587. TERN_(SQUARE_WAVE_STEPPING, st.dedge(true));
  588. st.intpol(interpolate);
  589. st.diss2g(true); // Disable short to ground protection. Too many false readings?
  590. TERN_(TMC_DEBUG, st.rdsel(0b01));
  591. }
  592. #endif // TMC2660
  593. #if HAS_DRIVER(TMC5130)
  594. template<char AXIS_LETTER, char DRIVER_ID, AxisEnum AXIS_ID>
  595. void tmc_init(TMCMarlin<TMC5130Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate) {
  596. st.begin();
  597. CHOPCONF_t chopconf{0};
  598. chopconf.tbl = 0b01;
  599. chopconf.toff = chop_init.toff;
  600. chopconf.intpol = interpolate;
  601. chopconf.hend = chop_init.hend + 3;
  602. chopconf.hstrt = chop_init.hstrt - 1;
  603. TERN_(SQUARE_WAVE_STEPPING, chopconf.dedge = true);
  604. st.CHOPCONF(chopconf.sr);
  605. st.rms_current(mA, HOLD_MULTIPLIER);
  606. st.microsteps(microsteps);
  607. st.iholddelay(10);
  608. st.TPOWERDOWN(128); // ~2s until driver lowers to hold current
  609. st.en_pwm_mode(stealth);
  610. st.stored.stealthChop_enabled = stealth;
  611. PWMCONF_t pwmconf{0};
  612. pwmconf.pwm_freq = 0b01; // f_pwm = 2/683 f_clk
  613. pwmconf.pwm_autoscale = true;
  614. pwmconf.pwm_grad = 5;
  615. pwmconf.pwm_ampl = 180;
  616. st.PWMCONF(pwmconf.sr);
  617. TERN(HYBRID_THRESHOLD, st.set_pwm_thrs(hyb_thrs), UNUSED(hyb_thrs));
  618. st.GSTAT(); // Clear GSTAT
  619. }
  620. #endif // TMC5130
  621. #if HAS_DRIVER(TMC5160)
  622. template<char AXIS_LETTER, char DRIVER_ID, AxisEnum AXIS_ID>
  623. void tmc_init(TMCMarlin<TMC5160Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate) {
  624. st.begin();
  625. CHOPCONF_t chopconf{0};
  626. chopconf.tbl = 0b01;
  627. chopconf.toff = chop_init.toff;
  628. chopconf.intpol = interpolate;
  629. chopconf.hend = chop_init.hend + 3;
  630. chopconf.hstrt = chop_init.hstrt - 1;
  631. TERN_(SQUARE_WAVE_STEPPING, chopconf.dedge = true);
  632. st.CHOPCONF(chopconf.sr);
  633. st.rms_current(mA, HOLD_MULTIPLIER);
  634. st.microsteps(microsteps);
  635. st.iholddelay(10);
  636. st.TPOWERDOWN(128); // ~2s until driver lowers to hold current
  637. st.en_pwm_mode(stealth);
  638. st.stored.stealthChop_enabled = stealth;
  639. TMC2160_n::PWMCONF_t pwmconf{0};
  640. pwmconf.pwm_lim = 12;
  641. pwmconf.pwm_reg = 8;
  642. pwmconf.pwm_autograd = true;
  643. pwmconf.pwm_autoscale = true;
  644. pwmconf.pwm_freq = 0b01;
  645. pwmconf.pwm_grad = 14;
  646. pwmconf.pwm_ofs = 36;
  647. st.PWMCONF(pwmconf.sr);
  648. #if ENABLED(HYBRID_THRESHOLD)
  649. st.set_pwm_thrs(hyb_thrs);
  650. #else
  651. UNUSED(hyb_thrs);
  652. #endif
  653. st.GSTAT(); // Clear GSTAT
  654. }
  655. #endif // TMC5160
  656. void restore_trinamic_drivers() {
  657. #if AXIS_IS_TMC(X)
  658. stepperX.push();
  659. #endif
  660. #if AXIS_IS_TMC(X2)
  661. stepperX2.push();
  662. #endif
  663. #if AXIS_IS_TMC(Y)
  664. stepperY.push();
  665. #endif
  666. #if AXIS_IS_TMC(Y2)
  667. stepperY2.push();
  668. #endif
  669. #if AXIS_IS_TMC(Z)
  670. stepperZ.push();
  671. #endif
  672. #if AXIS_IS_TMC(Z2)
  673. stepperZ2.push();
  674. #endif
  675. #if AXIS_IS_TMC(Z3)
  676. stepperZ3.push();
  677. #endif
  678. #if AXIS_IS_TMC(Z4)
  679. stepperZ4.push();
  680. #endif
  681. #if AXIS_IS_TMC(E0)
  682. stepperE0.push();
  683. #endif
  684. #if AXIS_IS_TMC(E1)
  685. stepperE1.push();
  686. #endif
  687. #if AXIS_IS_TMC(E2)
  688. stepperE2.push();
  689. #endif
  690. #if AXIS_IS_TMC(E3)
  691. stepperE3.push();
  692. #endif
  693. #if AXIS_IS_TMC(E4)
  694. stepperE4.push();
  695. #endif
  696. #if AXIS_IS_TMC(E5)
  697. stepperE5.push();
  698. #endif
  699. #if AXIS_IS_TMC(E6)
  700. stepperE6.push();
  701. #endif
  702. #if AXIS_IS_TMC(E7)
  703. stepperE7.push();
  704. #endif
  705. }
  706. void reset_trinamic_drivers() {
  707. static constexpr bool stealthchop_by_axis[] = LOGICAL_AXIS_ARRAY(
  708. ENABLED(STEALTHCHOP_E),
  709. ENABLED(STEALTHCHOP_XY),
  710. ENABLED(STEALTHCHOP_XY),
  711. ENABLED(STEALTHCHOP_Z)
  712. );
  713. #if AXIS_IS_TMC(X)
  714. TMC_INIT(X, STEALTH_AXIS_X);
  715. #endif
  716. #if AXIS_IS_TMC(X2)
  717. TMC_INIT(X2, STEALTH_AXIS_X);
  718. #endif
  719. #if AXIS_IS_TMC(Y)
  720. TMC_INIT(Y, STEALTH_AXIS_Y);
  721. #endif
  722. #if AXIS_IS_TMC(Y2)
  723. TMC_INIT(Y2, STEALTH_AXIS_Y);
  724. #endif
  725. #if AXIS_IS_TMC(Z)
  726. TMC_INIT(Z, STEALTH_AXIS_Z);
  727. #endif
  728. #if AXIS_IS_TMC(Z2)
  729. TMC_INIT(Z2, STEALTH_AXIS_Z);
  730. #endif
  731. #if AXIS_IS_TMC(Z3)
  732. TMC_INIT(Z3, STEALTH_AXIS_Z);
  733. #endif
  734. #if AXIS_IS_TMC(Z4)
  735. TMC_INIT(Z4, STEALTH_AXIS_Z);
  736. #endif
  737. #if AXIS_IS_TMC(E0)
  738. TMC_INIT(E0, STEALTH_AXIS_E);
  739. #endif
  740. #if AXIS_IS_TMC(E1)
  741. TMC_INIT(E1, STEALTH_AXIS_E);
  742. #endif
  743. #if AXIS_IS_TMC(E2)
  744. TMC_INIT(E2, STEALTH_AXIS_E);
  745. #endif
  746. #if AXIS_IS_TMC(E3)
  747. TMC_INIT(E3, STEALTH_AXIS_E);
  748. #endif
  749. #if AXIS_IS_TMC(E4)
  750. TMC_INIT(E4, STEALTH_AXIS_E);
  751. #endif
  752. #if AXIS_IS_TMC(E5)
  753. TMC_INIT(E5, STEALTH_AXIS_E);
  754. #endif
  755. #if AXIS_IS_TMC(E6)
  756. TMC_INIT(E6, STEALTH_AXIS_E);
  757. #endif
  758. #if AXIS_IS_TMC(E7)
  759. TMC_INIT(E7, STEALTH_AXIS_E);
  760. #endif
  761. #if USE_SENSORLESS
  762. #if X_SENSORLESS
  763. stepperX.homing_threshold(X_STALL_SENSITIVITY);
  764. #if AXIS_HAS_STALLGUARD(X2)
  765. stepperX2.homing_threshold(CAT(TERN(X2_SENSORLESS, X2, X), _STALL_SENSITIVITY));
  766. #endif
  767. #endif
  768. #if Y_SENSORLESS
  769. stepperY.homing_threshold(Y_STALL_SENSITIVITY);
  770. #if AXIS_HAS_STALLGUARD(Y2)
  771. stepperY2.homing_threshold(CAT(TERN(Y2_SENSORLESS, Y2, Y), _STALL_SENSITIVITY));
  772. #endif
  773. #endif
  774. #if Z_SENSORLESS
  775. stepperZ.homing_threshold(Z_STALL_SENSITIVITY);
  776. #if AXIS_HAS_STALLGUARD(Z2)
  777. stepperZ2.homing_threshold(CAT(TERN(Z2_SENSORLESS, Z2, Z), _STALL_SENSITIVITY));
  778. #endif
  779. #if AXIS_HAS_STALLGUARD(Z3)
  780. stepperZ3.homing_threshold(CAT(TERN(Z3_SENSORLESS, Z3, Z), _STALL_SENSITIVITY));
  781. #endif
  782. #if AXIS_HAS_STALLGUARD(Z4)
  783. stepperZ4.homing_threshold(CAT(TERN(Z4_SENSORLESS, Z4, Z), _STALL_SENSITIVITY));
  784. #endif
  785. #endif
  786. #endif // USE SENSORLESS
  787. #ifdef TMC_ADV
  788. TMC_ADV()
  789. #endif
  790. stepper.set_directions();
  791. }
  792. // TMC Slave Address Conflict Detection
  793. //
  794. // Conflict detection is performed in the following way. Similar methods are used for
  795. // hardware and software serial, but the implementations are indepenent.
  796. //
  797. // 1. Populate a data structure with UART parameters and addresses for all possible axis.
  798. // If an axis is not in use, populate it with recognizable placeholder data.
  799. // 2. For each axis in use, static_assert using a constexpr function, which counts the
  800. // number of matching/conflicting axis. If the value is not exactly 1, fail.
  801. #if ANY_AXIS_HAS(HW_SERIAL)
  802. // Hardware serial names are compared as strings, since actually resolving them cannot occur in a constexpr.
  803. // Using a fixed-length character array for the port name allows this to be constexpr compatible.
  804. struct SanityHwSerialDetails { const char port[20]; uint32_t address; };
  805. #define TMC_HW_DETAIL_ARGS(A) TERN(A##_HAS_HW_SERIAL, STRINGIFY(A##_HARDWARE_SERIAL), ""), TERN0(A##_HAS_HW_SERIAL, A##_SLAVE_ADDRESS)
  806. #define TMC_HW_DETAIL(A) {TMC_HW_DETAIL_ARGS(A)}
  807. constexpr SanityHwSerialDetails sanity_tmc_hw_details[] = {
  808. TMC_HW_DETAIL(X), TMC_HW_DETAIL(X2),
  809. TMC_HW_DETAIL(Y), TMC_HW_DETAIL(Y2),
  810. TMC_HW_DETAIL(Z), TMC_HW_DETAIL(Z2), TMC_HW_DETAIL(Z3), TMC_HW_DETAIL(Z4),
  811. TMC_HW_DETAIL(E0), TMC_HW_DETAIL(E1), TMC_HW_DETAIL(E2), TMC_HW_DETAIL(E3), TMC_HW_DETAIL(E4), TMC_HW_DETAIL(E5), TMC_HW_DETAIL(E6), TMC_HW_DETAIL(E7)
  812. };
  813. // constexpr compatible string comparison
  814. constexpr bool str_eq_ce(const char * a, const char * b) {
  815. return *a == *b && (*a == '\0' || str_eq_ce(a+1,b+1));
  816. }
  817. constexpr bool sc_hw_done(size_t start, size_t end) { return start == end; }
  818. constexpr bool sc_hw_skip(const char *port_name) { return !(*port_name); }
  819. constexpr bool sc_hw_match(const char *port_name, uint32_t address, size_t start, size_t end) {
  820. return !sc_hw_done(start, end) && !sc_hw_skip(port_name) && (address == sanity_tmc_hw_details[start].address && str_eq_ce(port_name, sanity_tmc_hw_details[start].port));
  821. }
  822. constexpr int count_tmc_hw_serial_matches(const char *port_name, uint32_t address, size_t start, size_t end) {
  823. return sc_hw_done(start, end) ? 0 : ((sc_hw_skip(port_name) ? 0 : (sc_hw_match(port_name, address, start, end) ? 1 : 0)) + count_tmc_hw_serial_matches(port_name, address, start + 1, end));
  824. }
  825. #define TMC_HWSERIAL_CONFLICT_MSG(A) STRINGIFY(A) "_SLAVE_ADDRESS conflicts with another driver using the same " STRINGIFY(A) "_HARDWARE_SERIAL"
  826. #define SA_NO_TMC_HW_C(A) static_assert(1 >= count_tmc_hw_serial_matches(TMC_HW_DETAIL_ARGS(A), 0, COUNT(sanity_tmc_hw_details)), TMC_HWSERIAL_CONFLICT_MSG(A));
  827. SA_NO_TMC_HW_C(X);SA_NO_TMC_HW_C(X2);
  828. SA_NO_TMC_HW_C(Y);SA_NO_TMC_HW_C(Y2);
  829. SA_NO_TMC_HW_C(Z);SA_NO_TMC_HW_C(Z2);SA_NO_TMC_HW_C(Z3);SA_NO_TMC_HW_C(Z4);
  830. SA_NO_TMC_HW_C(E0);SA_NO_TMC_HW_C(E1);SA_NO_TMC_HW_C(E2);SA_NO_TMC_HW_C(E3);SA_NO_TMC_HW_C(E4);SA_NO_TMC_HW_C(E5);SA_NO_TMC_HW_C(E6);SA_NO_TMC_HW_C(E7);
  831. #endif
  832. #if ANY_AXIS_HAS(SW_SERIAL)
  833. struct SanitySwSerialDetails { int32_t txpin; int32_t rxpin; uint32_t address; };
  834. #define TMC_SW_DETAIL_ARGS(A) TERN(A##_HAS_SW_SERIAL, A##_SERIAL_TX_PIN, -1), TERN(A##_HAS_SW_SERIAL, A##_SERIAL_RX_PIN, -1), TERN0(A##_HAS_SW_SERIAL, A##_SLAVE_ADDRESS)
  835. #define TMC_SW_DETAIL(A) TMC_SW_DETAIL_ARGS(A)
  836. constexpr SanitySwSerialDetails sanity_tmc_sw_details[] = {
  837. TMC_SW_DETAIL(X), TMC_SW_DETAIL(X2),
  838. TMC_SW_DETAIL(Y), TMC_SW_DETAIL(Y2),
  839. TMC_SW_DETAIL(Z), TMC_SW_DETAIL(Z2), TMC_SW_DETAIL(Z3), TMC_SW_DETAIL(Z4),
  840. TMC_SW_DETAIL(E0), TMC_SW_DETAIL(E1), TMC_SW_DETAIL(E2), TMC_SW_DETAIL(E3), TMC_SW_DETAIL(E4), TMC_SW_DETAIL(E5), TMC_SW_DETAIL(E6), TMC_SW_DETAIL(E7)
  841. };
  842. constexpr bool sc_sw_done(size_t start, size_t end) { return start == end; }
  843. constexpr bool sc_sw_skip(int32_t txpin) { return txpin < 0; }
  844. constexpr bool sc_sw_match(int32_t txpin, int32_t rxpin, uint32_t address, size_t start, size_t end) {
  845. return !sc_sw_done(start, end) && !sc_sw_skip(txpin) && (txpin == sanity_tmc_sw_details[start].txpin || rxpin == sanity_tmc_sw_details[start].rxpin) && (address == sanity_tmc_sw_details[start].address);
  846. }
  847. constexpr int count_tmc_sw_serial_matches(int32_t txpin, int32_t rxpin, uint32_t address, size_t start, size_t end) {
  848. return sc_sw_done(start, end) ? 0 : ((sc_sw_skip(txpin) ? 0 : (sc_sw_match(txpin, rxpin, address, start, end) ? 1 : 0)) + count_tmc_sw_serial_matches(txpin, rxpin, address, start + 1, end));
  849. }
  850. #define TMC_SWSERIAL_CONFLICT_MSG(A) STRINGIFY(A) "_SLAVE_ADDRESS conflicts with another driver using the same " STRINGIFY(A) "_SERIAL_RX_PIN or " STRINGIFY(A) "_SERIAL_TX_PIN"
  851. #define SA_NO_TMC_SW_C(A) static_assert(1 >= count_tmc_sw_serial_matches(TMC_SW_DETAIL_ARGS(A), 0, COUNT(sanity_tmc_sw_details)), TMC_SWSERIAL_CONFLICT_MSG(A));
  852. SA_NO_TMC_SW_C(X);SA_NO_TMC_SW_C(X2);
  853. SA_NO_TMC_SW_C(Y);SA_NO_TMC_SW_C(Y2);
  854. SA_NO_TMC_SW_C(Z);SA_NO_TMC_SW_C(Z2);SA_NO_TMC_SW_C(Z3);SA_NO_TMC_SW_C(Z4);
  855. SA_NO_TMC_SW_C(E0);SA_NO_TMC_SW_C(E1);SA_NO_TMC_SW_C(E2);SA_NO_TMC_SW_C(E3);SA_NO_TMC_SW_C(E4);SA_NO_TMC_SW_C(E5);SA_NO_TMC_SW_C(E6);SA_NO_TMC_SW_C(E7);
  856. #endif
  857. #endif // HAS_TRINAMIC_CONFIG