|
@@ -27,7 +27,6 @@
|
27
|
27
|
// Local defines
|
28
|
28
|
// ------------------------
|
29
|
29
|
|
30
|
|
-
|
31
|
30
|
// Default timer priorities. Override by specifying alternate priorities in the board pins file.
|
32
|
31
|
// The TONE timer is not present here, as it currently cannot be set programmatically. It is set
|
33
|
32
|
// by defining TIM_IRQ_PRIO in the variant.h or platformio.ini file, which adjusts the default
|
|
@@ -96,11 +95,6 @@
|
96
|
95
|
#define STEP_TIMER_DEV _TIMER_DEV(STEP_TIMER)
|
97
|
96
|
#define TEMP_TIMER_DEV _TIMER_DEV(TEMP_TIMER)
|
98
|
97
|
|
99
|
|
-#define __TIMER_IRQ_NAME(X) TIM##X##_IRQn
|
100
|
|
-#define _TIMER_IRQ_NAME(X) __TIMER_IRQ_NAME(X)
|
101
|
|
-#define STEP_TIMER_IRQ_NAME _TIMER_IRQ_NAME(STEP_TIMER)
|
102
|
|
-#define TEMP_TIMER_IRQ_NAME _TIMER_IRQ_NAME(TEMP_TIMER)
|
103
|
|
-
|
104
|
98
|
// ------------------------
|
105
|
99
|
// Private Variables
|
106
|
100
|
// ------------------------
|
|
@@ -197,87 +191,132 @@ void SetTimerInterruptPriorities() {
|
197
|
191
|
TERN_(HAS_SERVOS, libServo::setInterruptPriority(SERVO_TIMER_IRQ_PRIO, 0));
|
198
|
192
|
}
|
199
|
193
|
|
200
|
|
-// This is a terrible hack to replicate the behavior used in the framework's SoftwareSerial.cpp
|
201
|
|
-// to choose a serial timer. It will select TIM7 on most boards used by Marlin, but this is more
|
202
|
|
-// resiliant to new MCUs which may not have a TIM7. Best practice is to explicitly specify
|
203
|
|
-// TIMER_SERIAL to avoid relying on framework selections which may not be predictable.
|
204
|
|
-#if !defined(TIMER_SERIAL)
|
205
|
|
- #if defined (TIM18_BASE)
|
206
|
|
- #define TIMER_SERIAL TIM18
|
207
|
|
- #elif defined (TIM7_BASE)
|
208
|
|
- #define TIMER_SERIAL TIM7
|
209
|
|
- #elif defined (TIM6_BASE)
|
210
|
|
- #define TIMER_SERIAL TIM6
|
211
|
|
- #elif defined (TIM22_BASE)
|
212
|
|
- #define TIMER_SERIAL TIM22
|
213
|
|
- #elif defined (TIM21_BASE)
|
214
|
|
- #define TIMER_SERIAL TIM21
|
215
|
|
- #elif defined (TIM17_BASE)
|
216
|
|
- #define TIMER_SERIAL TIM17
|
217
|
|
- #elif defined (TIM16_BASE)
|
218
|
|
- #define TIMER_SERIAL TIM16
|
219
|
|
- #elif defined (TIM15_BASE)
|
220
|
|
- #define TIMER_SERIAL TIM15
|
221
|
|
- #elif defined (TIM14_BASE)
|
222
|
|
- #define TIMER_SERIAL TIM14
|
223
|
|
- #elif defined (TIM13_BASE)
|
224
|
|
- #define TIMER_SERIAL TIM13
|
225
|
|
- #elif defined (TIM11_BASE)
|
226
|
|
- #define TIMER_SERIAL TIM11
|
227
|
|
- #elif defined (TIM10_BASE)
|
228
|
|
- #define TIMER_SERIAL TIM10
|
229
|
|
- #elif defined (TIM12_BASE)
|
230
|
|
- #define TIMER_SERIAL TIM12
|
231
|
|
- #elif defined (TIM19_BASE)
|
232
|
|
- #define TIMER_SERIAL TIM19
|
233
|
|
- #elif defined (TIM9_BASE)
|
234
|
|
- #define TIMER_SERIAL TIM9
|
235
|
|
- #elif defined (TIM5_BASE)
|
236
|
|
- #define TIMER_SERIAL TIM5
|
237
|
|
- #elif defined (TIM4_BASE)
|
238
|
|
- #define TIMER_SERIAL TIM4
|
239
|
|
- #elif defined (TIM3_BASE)
|
240
|
|
- #define TIMER_SERIAL TIM3
|
241
|
|
- #elif defined (TIM2_BASE)
|
242
|
|
- #define TIMER_SERIAL TIM2
|
243
|
|
- #elif defined (TIM20_BASE)
|
244
|
|
- #define TIMER_SERIAL TIM20
|
245
|
|
- #elif defined (TIM8_BASE)
|
246
|
|
- #define TIMER_SERIAL TIM8
|
247
|
|
- #elif defined (TIM1_BASE)
|
248
|
|
- #define TIMER_SERIAL TIM1
|
249
|
|
- #else
|
250
|
|
- #error No suitable timer found for SoftwareSerial, define TIMER_SERIAL in variant.h
|
|
194
|
+// ------------------------
|
|
195
|
+// Detect timer conflicts
|
|
196
|
+// ------------------------
|
|
197
|
+
|
|
198
|
+// This list serves two purposes. Firstly, it facilitates build-time mapping between
|
|
199
|
+// variant-defined timer names (such as TIM1) and timer numbers. It also replicates
|
|
200
|
+// the order of timers used in the framework's SoftwareSerial.cpp. The first timer in
|
|
201
|
+// this list will be automatically used by SoftwareSerial if it is not already defined
|
|
202
|
+// in the board's variant or compiler options.
|
|
203
|
+static constexpr struct {uintptr_t base_address; int timer_number;} stm32_timer_map[] = {
|
|
204
|
+ #ifdef TIM18_BASE
|
|
205
|
+ { uintptr_t(TIM18), 18 },
|
|
206
|
+ #endif
|
|
207
|
+ #ifdef TIM7_BASE
|
|
208
|
+ { uintptr_t(TIM7), 7 },
|
|
209
|
+ #endif
|
|
210
|
+ #ifdef TIM6_BASE
|
|
211
|
+ { uintptr_t(TIM6), 6 },
|
|
212
|
+ #endif
|
|
213
|
+ #ifdef TIM22_BASE
|
|
214
|
+ { uintptr_t(TIM22), 22 },
|
|
215
|
+ #endif
|
|
216
|
+ #ifdef TIM21_BASE
|
|
217
|
+ { uintptr_t(TIM21), 21 },
|
|
218
|
+ #endif
|
|
219
|
+ #ifdef TIM17_BASE
|
|
220
|
+ { uintptr_t(TIM17), 17 },
|
|
221
|
+ #endif
|
|
222
|
+ #ifdef TIM16_BASE
|
|
223
|
+ { uintptr_t(TIM16), 16 },
|
|
224
|
+ #endif
|
|
225
|
+ #ifdef TIM15_BASE
|
|
226
|
+ { uintptr_t(TIM15), 15 },
|
|
227
|
+ #endif
|
|
228
|
+ #ifdef TIM14_BASE
|
|
229
|
+ { uintptr_t(TIM14), 14 },
|
|
230
|
+ #endif
|
|
231
|
+ #ifdef TIM13_BASE
|
|
232
|
+ { uintptr_t(TIM13), 13 },
|
|
233
|
+ #endif
|
|
234
|
+ #ifdef TIM11_BASE
|
|
235
|
+ { uintptr_t(TIM11), 11 },
|
|
236
|
+ #endif
|
|
237
|
+ #ifdef TIM10_BASE
|
|
238
|
+ { uintptr_t(TIM10), 10 },
|
251
|
239
|
#endif
|
|
240
|
+ #ifdef TIM12_BASE
|
|
241
|
+ { uintptr_t(TIM12), 12 },
|
|
242
|
+ #endif
|
|
243
|
+ #ifdef TIM19_BASE
|
|
244
|
+ { uintptr_t(TIM19), 19 },
|
|
245
|
+ #endif
|
|
246
|
+ #ifdef TIM9_BASE
|
|
247
|
+ { uintptr_t(TIM9), 9 },
|
|
248
|
+ #endif
|
|
249
|
+ #ifdef TIM5_BASE
|
|
250
|
+ { uintptr_t(TIM5), 5 },
|
|
251
|
+ #endif
|
|
252
|
+ #ifdef TIM4_BASE
|
|
253
|
+ { uintptr_t(TIM4), 4 },
|
|
254
|
+ #endif
|
|
255
|
+ #ifdef TIM3_BASE
|
|
256
|
+ { uintptr_t(TIM3), 3 },
|
|
257
|
+ #endif
|
|
258
|
+ #ifdef TIM2_BASE
|
|
259
|
+ { uintptr_t(TIM2), 2 },
|
|
260
|
+ #endif
|
|
261
|
+ #ifdef TIM20_BASE
|
|
262
|
+ { uintptr_t(TIM20), 20 },
|
|
263
|
+ #endif
|
|
264
|
+ #ifdef TIM8_BASE
|
|
265
|
+ { uintptr_t(TIM8), 8 },
|
|
266
|
+ #endif
|
|
267
|
+ #ifdef TIM1_BASE
|
|
268
|
+ { uintptr_t(TIM1), 1 }
|
|
269
|
+ #endif
|
|
270
|
+};
|
|
271
|
+
|
|
272
|
+// Convert from a timer base address to its integer timer number.
|
|
273
|
+static constexpr int get_timer_num_from_base_address(uintptr_t base_address) {
|
|
274
|
+ for (const auto &timer : stm32_timer_map)
|
|
275
|
+ if (timer.base_address == base_address) return timer.timer_number;
|
|
276
|
+ return 0;
|
|
277
|
+}
|
|
278
|
+
|
|
279
|
+// The platform's SoftwareSerial.cpp will use the first timer from stm32_timer_map.
|
|
280
|
+#if HAS_TMC_SW_SERIAL && !defined(TIMER_SERIAL)
|
|
281
|
+ #define TIMER_SERIAL (stm32_timer_map[0].base_address)
|
252
|
282
|
#endif
|
253
|
283
|
|
254
|
|
-// Place all timers used into an array, then recursively check for duplicates during compilation.
|
255
|
|
-// This does not currently account for timers used for PWM, such as for fans.
|
256
|
|
-// Timers are actually pointers. Convert to integers to simplify constexpr logic.
|
257
|
|
-static constexpr uintptr_t timers_in_use[] = {
|
258
|
|
- uintptr_t(TEMP_TIMER_DEV), // Override in pins file
|
259
|
|
- uintptr_t(STEP_TIMER_DEV), // Override in pins file
|
|
284
|
+// constexpr doesn't like using the base address pointers that timers evaluate to.
|
|
285
|
+// We can get away with casting them to uintptr_t, if we do so inside an array.
|
|
286
|
+// GCC will not currently do it directly to a uintptr_t.
|
|
287
|
+IF_ENABLED(HAS_TMC_SW_SERIAL, static constexpr uintptr_t timer_serial[] = {uintptr_t(TIMER_SERIAL)});
|
|
288
|
+IF_ENABLED(SPEAKER, static constexpr uintptr_t timer_tone[] = {uintptr_t(TIMER_TONE)});
|
|
289
|
+IF_ENABLED(HAS_SERVOS, static constexpr uintptr_t timer_servo[] = {uintptr_t(TIMER_SERVO)});
|
|
290
|
+
|
|
291
|
+enum TimerPurpose { TP_SERIAL, TP_TONE, TP_SERVO, TP_STEP, TP_TEMP };
|
|
292
|
+
|
|
293
|
+// List of timers, to enable checking for conflicts.
|
|
294
|
+// Includes the purpose of each timer to ease debugging when evaluating at build-time.
|
|
295
|
+// This cannot yet account for timers used for PWM output, such as for fans.
|
|
296
|
+static constexpr struct { TimerPurpose p; int t; } timers_in_use[] = {
|
260
|
297
|
#if HAS_TMC_SW_SERIAL
|
261
|
|
- uintptr_t(TIMER_SERIAL), // Set in variant.h, or as a define in platformio.h if not present in variant.h
|
|
298
|
+ {TP_SERIAL, get_timer_num_from_base_address(timer_serial[0])}, // Set in variant.h, or as a define in platformio.h if not present in variant.h
|
262
|
299
|
#endif
|
263
|
300
|
#if ENABLED(SPEAKER)
|
264
|
|
- uintptr_t(TIMER_TONE), // Set in variant.h, or as a define in platformio.h if not present in variant.h
|
|
301
|
+ {TP_TONE, get_timer_num_from_base_address(timer_tone[0])}, // Set in variant.h, or as a define in platformio.h if not present in variant.h
|
265
|
302
|
#endif
|
266
|
303
|
#if HAS_SERVOS
|
267
|
|
- uintptr_t(TIMER_SERVO), // Set in variant.h, or as a define in platformio.h if not present in variant.h
|
|
304
|
+ {TP_SERVO, get_timer_num_from_base_address(timer_servo[0])}, // Set in variant.h, or as a define in platformio.h if not present in variant.h
|
268
|
305
|
#endif
|
269
|
|
- };
|
|
306
|
+ {TP_STEP, STEP_TIMER},
|
|
307
|
+ {TP_TEMP, TEMP_TIMER},
|
|
308
|
+};
|
270
|
309
|
|
271
|
|
-static constexpr bool verify_no_duplicate_timers() {
|
|
310
|
+static constexpr bool verify_no_timer_conflicts() {
|
272
|
311
|
LOOP_L_N(i, COUNT(timers_in_use))
|
273
|
312
|
LOOP_S_L_N(j, i + 1, COUNT(timers_in_use))
|
274
|
|
- if (timers_in_use[i] == timers_in_use[j]) return false;
|
|
313
|
+ if (timers_in_use[i].t == timers_in_use[j].t) return false;
|
275
|
314
|
return true;
|
276
|
315
|
}
|
277
|
316
|
|
278
|
|
-// If this assertion fails at compile time, review the timers_in_use array. If default_envs is
|
279
|
|
-// defined properly in platformio.ini, VS Code can evaluate the array when hovering over it,
|
280
|
|
-// making it easy to identify the conflicting timers.
|
281
|
|
-static_assert(verify_no_duplicate_timers(), "One or more timer conflict detected");
|
|
317
|
+// If this assertion fails at compile time, review the timers_in_use array.
|
|
318
|
+// If default_envs is defined properly in platformio.ini, VS Code can evaluate the array
|
|
319
|
+// when hovering over it, making it easy to identify the conflicting timers.
|
|
320
|
+static_assert(verify_no_timer_conflicts(), "One or more timer conflict detected. Examine \"timers_in_use\" to help identify conflict.");
|
282
|
321
|
|
283
|
322
|
#endif // ARDUINO_ARCH_STM32 && !STM32GENERIC
|