|
@@ -209,113 +209,145 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
|
209
|
209
|
#if AXIS_HAS_UART(X)
|
210
|
210
|
#ifdef X_HARDWARE_SERIAL
|
211
|
211
|
TMC_UART_DEFINE(HW, X, X);
|
|
212
|
+ #define X_HAS_HW_SERIAL 1
|
212
|
213
|
#else
|
213
|
214
|
TMC_UART_DEFINE(SW, X, X);
|
|
215
|
+ #define X_HAS_SW_SERIAL 1
|
214
|
216
|
#endif
|
215
|
217
|
#endif
|
216
|
218
|
#if AXIS_HAS_UART(X2)
|
217
|
219
|
#ifdef X2_HARDWARE_SERIAL
|
218
|
220
|
TMC_UART_DEFINE(HW, X2, X);
|
|
221
|
+ #define X2_HAS_HW_SERIAL 1
|
219
|
222
|
#else
|
220
|
223
|
TMC_UART_DEFINE(SW, X2, X);
|
|
224
|
+ #define X2_HAS_SW_SERIAL 1
|
221
|
225
|
#endif
|
222
|
226
|
#endif
|
223
|
227
|
#if AXIS_HAS_UART(Y)
|
224
|
228
|
#ifdef Y_HARDWARE_SERIAL
|
225
|
229
|
TMC_UART_DEFINE(HW, Y, Y);
|
|
230
|
+ #define Y_HAS_HW_SERIAL 1
|
226
|
231
|
#else
|
227
|
232
|
TMC_UART_DEFINE(SW, Y, Y);
|
|
233
|
+ #define Y_HAS_SW_SERIAL 1
|
228
|
234
|
#endif
|
229
|
235
|
#endif
|
230
|
236
|
#if AXIS_HAS_UART(Y2)
|
231
|
237
|
#ifdef Y2_HARDWARE_SERIAL
|
232
|
238
|
TMC_UART_DEFINE(HW, Y2, Y);
|
|
239
|
+ #define Y2_HAS_HW_SERIAL 1
|
233
|
240
|
#else
|
234
|
241
|
TMC_UART_DEFINE(SW, Y2, Y);
|
|
242
|
+ #define Y2_HAS_SW_SERIAL 1
|
235
|
243
|
#endif
|
236
|
244
|
#endif
|
237
|
245
|
#if AXIS_HAS_UART(Z)
|
238
|
246
|
#ifdef Z_HARDWARE_SERIAL
|
239
|
247
|
TMC_UART_DEFINE(HW, Z, Z);
|
|
248
|
+ #define Z_HAS_HW_SERIAL 1
|
240
|
249
|
#else
|
241
|
250
|
TMC_UART_DEFINE(SW, Z, Z);
|
|
251
|
+ #define Z_HAS_SW_SERIAL 1
|
242
|
252
|
#endif
|
243
|
253
|
#endif
|
244
|
254
|
#if AXIS_HAS_UART(Z2)
|
245
|
255
|
#ifdef Z2_HARDWARE_SERIAL
|
246
|
256
|
TMC_UART_DEFINE(HW, Z2, Z);
|
|
257
|
+ #define Z2_HAS_HW_SERIAL 1
|
247
|
258
|
#else
|
248
|
259
|
TMC_UART_DEFINE(SW, Z2, Z);
|
|
260
|
+ #define Z2_HAS_SW_SERIAL 1
|
249
|
261
|
#endif
|
250
|
262
|
#endif
|
251
|
263
|
#if AXIS_HAS_UART(Z3)
|
252
|
264
|
#ifdef Z3_HARDWARE_SERIAL
|
253
|
265
|
TMC_UART_DEFINE(HW, Z3, Z);
|
|
266
|
+ #define Z3_HAS_HW_SERIAL 1
|
254
|
267
|
#else
|
255
|
268
|
TMC_UART_DEFINE(SW, Z3, Z);
|
|
269
|
+ #define Z3_HAS_SW_SERIAL 1
|
256
|
270
|
#endif
|
257
|
271
|
#endif
|
258
|
272
|
#if AXIS_HAS_UART(Z4)
|
259
|
273
|
#ifdef Z4_HARDWARE_SERIAL
|
260
|
274
|
TMC_UART_DEFINE(HW, Z4, Z);
|
|
275
|
+ #define Z4_HAS_HW_SERIAL 1
|
261
|
276
|
#else
|
262
|
277
|
TMC_UART_DEFINE(SW, Z4, Z);
|
|
278
|
+ #define Z4_HAS_SW_SERIAL 1
|
263
|
279
|
#endif
|
264
|
280
|
#endif
|
265
|
281
|
#if AXIS_HAS_UART(E0)
|
266
|
282
|
#ifdef E0_HARDWARE_SERIAL
|
267
|
283
|
TMC_UART_DEFINE_E(HW, 0);
|
|
284
|
+ #define E0_HAS_HW_SERIAL 1
|
268
|
285
|
#else
|
269
|
286
|
TMC_UART_DEFINE_E(SW, 0);
|
|
287
|
+ #define E0_HAS_SW_SERIAL 1
|
270
|
288
|
#endif
|
271
|
289
|
#endif
|
272
|
290
|
#if AXIS_HAS_UART(E1)
|
273
|
291
|
#ifdef E1_HARDWARE_SERIAL
|
274
|
292
|
TMC_UART_DEFINE_E(HW, 1);
|
|
293
|
+ #define E1_HAS_HW_SERIAL 1
|
275
|
294
|
#else
|
276
|
295
|
TMC_UART_DEFINE_E(SW, 1);
|
|
296
|
+ #define E1_HAS_SW_SERIAL 1
|
277
|
297
|
#endif
|
278
|
298
|
#endif
|
279
|
299
|
#if AXIS_HAS_UART(E2)
|
280
|
300
|
#ifdef E2_HARDWARE_SERIAL
|
281
|
301
|
TMC_UART_DEFINE_E(HW, 2);
|
|
302
|
+ #define E2_HAS_HW_SERIAL 1
|
282
|
303
|
#else
|
283
|
304
|
TMC_UART_DEFINE_E(SW, 2);
|
|
305
|
+ #define E2_HAS_SW_SERIAL 1
|
284
|
306
|
#endif
|
285
|
307
|
#endif
|
286
|
308
|
#if AXIS_HAS_UART(E3)
|
287
|
309
|
#ifdef E3_HARDWARE_SERIAL
|
288
|
310
|
TMC_UART_DEFINE_E(HW, 3);
|
|
311
|
+ #define E3_HAS_HW_SERIAL 1
|
289
|
312
|
#else
|
290
|
313
|
TMC_UART_DEFINE_E(SW, 3);
|
|
314
|
+ #define E3_HAS_SW_SERIAL 1
|
291
|
315
|
#endif
|
292
|
316
|
#endif
|
293
|
317
|
#if AXIS_HAS_UART(E4)
|
294
|
318
|
#ifdef E4_HARDWARE_SERIAL
|
295
|
319
|
TMC_UART_DEFINE_E(HW, 4);
|
|
320
|
+ #define E4_HAS_HW_SERIAL 1
|
296
|
321
|
#else
|
297
|
322
|
TMC_UART_DEFINE_E(SW, 4);
|
|
323
|
+ #define E4_HAS_SW_SERIAL 1
|
298
|
324
|
#endif
|
299
|
325
|
#endif
|
300
|
326
|
#if AXIS_HAS_UART(E5)
|
301
|
327
|
#ifdef E5_HARDWARE_SERIAL
|
302
|
328
|
TMC_UART_DEFINE_E(HW, 5);
|
|
329
|
+ #define E5_HAS_HW_SERIAL 1
|
303
|
330
|
#else
|
304
|
331
|
TMC_UART_DEFINE_E(SW, 5);
|
|
332
|
+ #define E5_HAS_SW_SERIAL 1
|
305
|
333
|
#endif
|
306
|
334
|
#endif
|
307
|
335
|
#if AXIS_HAS_UART(E6)
|
308
|
336
|
#ifdef E6_HARDWARE_SERIAL
|
309
|
337
|
TMC_UART_DEFINE_E(HW, 6);
|
|
338
|
+ #define E6_HAS_HW_SERIAL 1
|
310
|
339
|
#else
|
311
|
340
|
TMC_UART_DEFINE_E(SW, 6);
|
|
341
|
+ #define E6_HAS_SW_SERIAL 1
|
312
|
342
|
#endif
|
313
|
343
|
#endif
|
314
|
344
|
#if AXIS_HAS_UART(E7)
|
315
|
345
|
#ifdef E7_HARDWARE_SERIAL
|
316
|
346
|
TMC_UART_DEFINE_E(HW, 7);
|
|
347
|
+ #define E7_HAS_HW_SERIAL 1
|
317
|
348
|
#else
|
318
|
349
|
TMC_UART_DEFINE_E(SW, 7);
|
|
350
|
+ #define E7_HAS_SW_SERIAL 1
|
319
|
351
|
#endif
|
320
|
352
|
#endif
|
321
|
353
|
|
|
@@ -769,4 +801,77 @@ void reset_trinamic_drivers() {
|
769
|
801
|
stepper.set_directions();
|
770
|
802
|
}
|
771
|
803
|
|
|
804
|
+// TMC Slave Address Conflict Detection
|
|
805
|
+//
|
|
806
|
+// Conflict detection is performed in the following way. Similar methods are used for
|
|
807
|
+// hardware and software serial, but the implementations are indepenent.
|
|
808
|
+//
|
|
809
|
+// 1. Populate a data structure with UART parameters and addresses for all possible axis.
|
|
810
|
+// If an axis is not in use, populate it with recognizable placeholder data.
|
|
811
|
+// 2. For each axis in use, static_assert using a constexpr function, which counts the
|
|
812
|
+// number of matching/conflicting axis. If the value is not exactly 1, fail.
|
|
813
|
+
|
|
814
|
+#if ANY_AXIS_HAS(HW_SERIAL)
|
|
815
|
+ // Hardware serial names are compared as strings, since actually resolving them cannot occur in a constexpr.
|
|
816
|
+ // Using a fixed-length character array for the port name allows this to be constexpr compatible.
|
|
817
|
+ struct SanityHwSerialDetails { const char port[20]; uint32_t address; };
|
|
818
|
+ #define TMC_HW_DETAIL_ARGS(A) TERN(A##_HAS_HW_SERIAL, STRINGIFY(A##_HARDWARE_SERIAL), ""), TERN0(A##_HAS_HW_SERIAL, A##_SLAVE_ADDRESS)
|
|
819
|
+ #define TMC_HW_DETAIL(A) {TMC_HW_DETAIL_ARGS(A)}
|
|
820
|
+ constexpr SanityHwSerialDetails sanity_tmc_hw_details[] = {
|
|
821
|
+ TMC_HW_DETAIL(X), TMC_HW_DETAIL(X2),
|
|
822
|
+ TMC_HW_DETAIL(Y), TMC_HW_DETAIL(Y2),
|
|
823
|
+ TMC_HW_DETAIL(Z), TMC_HW_DETAIL(Z2), TMC_HW_DETAIL(Z3), TMC_HW_DETAIL(Z4),
|
|
824
|
+ 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)
|
|
825
|
+ };
|
|
826
|
+
|
|
827
|
+ // constexpr compatible string comparison
|
|
828
|
+ constexpr bool str_eq_ce(const char * a, const char * b) {
|
|
829
|
+ return *a == *b && (*a == '\0' || str_eq_ce(a+1,b+1));
|
|
830
|
+ }
|
|
831
|
+
|
|
832
|
+ constexpr bool sc_hw_done(size_t start, size_t end) { return start == end; }
|
|
833
|
+ constexpr bool sc_hw_skip(const char* port_name) { return !(*port_name); }
|
|
834
|
+ constexpr bool sc_hw_match(const char* port_name, uint32_t address, size_t start, size_t end) {
|
|
835
|
+ 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));
|
|
836
|
+ }
|
|
837
|
+ constexpr int count_tmc_hw_serial_matches(const char* port_name, uint32_t address, size_t start, size_t end) {
|
|
838
|
+ 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));
|
|
839
|
+ }
|
|
840
|
+
|
|
841
|
+ #define TMC_HWSERIAL_CONFLICT_MSG(A) STRINGIFY(A) "_SLAVE_ADDRESS conflicts with another driver using the same " STRINGIFY(A) "_HARDWARE_SERIAL"
|
|
842
|
+ #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));
|
|
843
|
+ SA_NO_TMC_HW_C(X);SA_NO_TMC_HW_C(X2);
|
|
844
|
+ SA_NO_TMC_HW_C(Y);SA_NO_TMC_HW_C(Y2);
|
|
845
|
+ SA_NO_TMC_HW_C(Z);SA_NO_TMC_HW_C(Z2);SA_NO_TMC_HW_C(Z3);SA_NO_TMC_HW_C(Z4);
|
|
846
|
+ 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);
|
|
847
|
+#endif
|
|
848
|
+
|
|
849
|
+#if ANY_AXIS_HAS(SW_SERIAL)
|
|
850
|
+ struct SanitySwSerialDetails { int32_t txpin; int32_t rxpin; uint32_t address; };
|
|
851
|
+ #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)
|
|
852
|
+ #define TMC_SW_DETAIL(A) TMC_SW_DETAIL_ARGS(A)
|
|
853
|
+ constexpr SanitySwSerialDetails sanity_tmc_sw_details[] = {
|
|
854
|
+ TMC_SW_DETAIL(X), TMC_SW_DETAIL(X2),
|
|
855
|
+ TMC_SW_DETAIL(Y), TMC_SW_DETAIL(Y2),
|
|
856
|
+ TMC_SW_DETAIL(Z), TMC_SW_DETAIL(Z2), TMC_SW_DETAIL(Z3), TMC_SW_DETAIL(Z4),
|
|
857
|
+ 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)
|
|
858
|
+ };
|
|
859
|
+
|
|
860
|
+ constexpr bool sc_sw_done(size_t start, size_t end) { return start == end; }
|
|
861
|
+ constexpr bool sc_sw_skip(int32_t txpin) { return txpin < 0; }
|
|
862
|
+ constexpr bool sc_sw_match(int32_t txpin, int32_t rxpin, uint32_t address, size_t start, size_t end) {
|
|
863
|
+ 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);
|
|
864
|
+ }
|
|
865
|
+ constexpr int count_tmc_sw_serial_matches(int32_t txpin, int32_t rxpin, uint32_t address, size_t start, size_t end) {
|
|
866
|
+ 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));
|
|
867
|
+ }
|
|
868
|
+
|
|
869
|
+ #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"
|
|
870
|
+ #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));
|
|
871
|
+ SA_NO_TMC_SW_C(X);SA_NO_TMC_SW_C(X2);
|
|
872
|
+ SA_NO_TMC_SW_C(Y);SA_NO_TMC_SW_C(Y2);
|
|
873
|
+ SA_NO_TMC_SW_C(Z);SA_NO_TMC_SW_C(Z2);SA_NO_TMC_SW_C(Z3);SA_NO_TMC_SW_C(Z4);
|
|
874
|
+ 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);
|
|
875
|
+#endif
|
|
876
|
+
|
772
|
877
|
#endif // HAS_TRINAMIC_CONFIG
|