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 31KB

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