@@ -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
0 commit comments