浏览代码

Merge pull request #10688 from ejtagle/bugfix-2.0.x

[2.0.x] Refactor, optimization of core planner/stepper/endstops logic
Scott Lahteine 7 年前
父节点
当前提交
16f92dca44
没有帐户链接到提交者的电子邮件
共有 37 个文件被更改,包括 1666 次插入1141 次删除
  1. 142
    18
      Marlin/src/HAL/HAL_AVR/HAL.h
  2. 7
    14
      Marlin/src/HAL/HAL_AVR/endstop_interrupts.h
  3. 5
    0
      Marlin/src/HAL/HAL_DUE/DebugMonitor_Due.cpp
  4. 21
    6
      Marlin/src/HAL/HAL_DUE/HAL_timers_Due.cpp
  5. 0
    2
      Marlin/src/HAL/HAL_DUE/HAL_timers_Due.h
  6. 10
    0
      Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp
  7. 3
    9
      Marlin/src/HAL/HAL_DUE/endstop_interrupts.h
  8. 5
    0
      Marlin/src/HAL/HAL_DUE/watchdog_Due.cpp
  9. 13
    40
      Marlin/src/HAL/HAL_LPC1768/HAL_timers.cpp
  10. 78
    36
      Marlin/src/HAL/HAL_LPC1768/HAL_timers.h
  11. 24
    1
      Marlin/src/HAL/HAL_LPC1768/LPC1768_PWM.cpp
  12. 3
    9
      Marlin/src/HAL/HAL_LPC1768/endstop_interrupts.h
  13. 3
    9
      Marlin/src/HAL/HAL_STM32F1/endstop_interrupts.h
  14. 5
    0
      Marlin/src/HAL/HAL_STM32F4/HAL_timers_STM32F4.cpp
  15. 2
    8
      Marlin/src/HAL/HAL_STM32F4/endstop_interrupts.h
  16. 5
    0
      Marlin/src/HAL/HAL_STM32F7/HAL_timers_STM32F7.cpp
  17. 2
    8
      Marlin/src/HAL/HAL_STM32F7/endstop_interrupts.h
  18. 21
    0
      Marlin/src/HAL/HAL_TEENSY35_36/HAL_timers_Teensy.cpp
  19. 3
    9
      Marlin/src/HAL/HAL_TEENSY35_36/endstop_interrupts.h
  20. 4
    10
      Marlin/src/Marlin.cpp
  21. 0
    4
      Marlin/src/feature/Max7219_Debug_LEDs.cpp
  22. 6
    3
      Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp
  23. 1
    1
      Marlin/src/gcode/config/M540.cpp
  24. 1
    1
      Marlin/src/gcode/control/M17_M18_M84.cpp
  25. 1
    1
      Marlin/src/gcode/control/M80_M81.cpp
  26. 6
    3
      Marlin/src/gcode/motion/G2_G3.cpp
  27. 2
    4
      Marlin/src/lcd/ultralcd.cpp
  28. 210
    120
      Marlin/src/module/endstops.cpp
  29. 20
    29
      Marlin/src/module/endstops.h
  30. 12
    9
      Marlin/src/module/motion.cpp
  31. 475
    252
      Marlin/src/module/planner.cpp
  32. 185
    90
      Marlin/src/module/planner.h
  33. 4
    2
      Marlin/src/module/planner_bezier.cpp
  34. 328
    321
      Marlin/src/module/stepper.cpp
  35. 52
    102
      Marlin/src/module/stepper.h
  36. 6
    18
      Marlin/src/module/temperature.cpp
  37. 1
    2
      Marlin/src/sd/cardreader.cpp

+ 142
- 18
Marlin/src/HAL/HAL_AVR/HAL.h 查看文件

@@ -162,24 +162,148 @@ extern "C" {
162 162
  * (otherwise, characters will be lost due to UART overflow).
163 163
  * Then: Stepper, Endstops, Temperature, and -finally- all others.
164 164
  */
165
-#define HAL_timer_isr_prologue_0 do{ DISABLE_TEMPERATURE_INTERRUPT(); sei(); }while(0)
166
-#define HAL_timer_isr_epilogue_0 do{ cli(); ENABLE_TEMPERATURE_INTERRUPT(); }while(0)
167
-
168
-#define HAL_timer_isr_prologue_1 \
169
-  const bool temp_isr_was_enabled = TEMPERATURE_ISR_ENABLED(); \
170
-  do{ \
171
-    DISABLE_TEMPERATURE_INTERRUPT(); \
172
-    DISABLE_STEPPER_DRIVER_INTERRUPT(); \
173
-    sei(); \
174
-  }while(0)
175
-
176
-#define HAL_timer_isr_epilogue_1 do{ cli(); ENABLE_STEPPER_DRIVER_INTERRUPT(); if (temp_isr_was_enabled) ENABLE_TEMPERATURE_INTERRUPT(); }while(0)
177
-
178
-#define HAL_timer_isr_prologue(TIMER_NUM) _CAT(HAL_timer_isr_prologue_, TIMER_NUM)
179
-#define HAL_timer_isr_epilogue(TIMER_NUM) _CAT(HAL_timer_isr_epilogue_, TIMER_NUM)
180
-
181
-#define HAL_STEP_TIMER_ISR ISR(TIMER1_COMPA_vect)
182
-#define HAL_TEMP_TIMER_ISR ISR(TIMER0_COMPB_vect)
165
+#define HAL_timer_isr_prologue(TIMER_NUM)
166
+#define HAL_timer_isr_epilogue(TIMER_NUM)
167
+
168
+/* 18 cycles maximum latency */
169
+#define HAL_STEP_TIMER_ISR \
170
+extern "C" void TIMER1_COMPA_vect (void) __attribute__ ((signal, naked, used, externally_visible)); \
171
+extern "C" void TIMER1_COMPA_vect_bottom (void) asm ("TIMER1_COMPA_vect_bottom") __attribute__ ((used, externally_visible, noinline)); \
172
+void TIMER1_COMPA_vect (void) { \
173
+  __asm__ __volatile__ ( \
174
+    A("push r16")                      /* 2 Save R16 */ \
175
+    A("in r16, __SREG__")              /* 1 Get SREG */ \
176
+    A("push r16")                      /* 2 Save SREG into stack */ \
177
+    A("lds r16, %[timsk0]")            /* 2 Load into R0 the Temperature timer Interrupt mask register */ \
178
+    A("push r16")                      /* 2 Save TIMSK0 into the stack */ \
179
+    A("andi r16,~%[msk0]")             /* 1 Disable the temperature ISR */ \
180
+    A("sts %[timsk0], r16")            /* 2 And set the new value */ \
181
+    A("lds r16, %[timsk1]")            /* 2 Load into R0 the stepper timer Interrupt mask register [TIMSK1] */ \
182
+    A("andi r16,~%[msk1]")             /* 1 Disable the stepper ISR */ \
183
+    A("sts %[timsk1], r16")            /* 2 And set the new value */ \
184
+    A("sei")                           /* 1 Enable global interrupts - stepper and temperature ISRs are disabled, so no risk of reentry or being preempted by the temperature ISR */    \
185
+    A("push r16")                      /* 2 Save TIMSK1 into stack */ \
186
+    A("in r16, 0x3B")                  /* 1 Get RAMPZ register */ \
187
+    A("push r16")                      /* 2 Save RAMPZ into stack */ \
188
+    A("in r16, 0x3C")                  /* 1 Get EIND register */ \
189
+    A("push r0")                       /* C runtime can modify all the following registers without restoring them */ \
190
+    A("push r1")                       \
191
+    A("push r18")                      \
192
+    A("push r19")                      \
193
+    A("push r20")                      \
194
+    A("push r21")                      \
195
+    A("push r22")                      \
196
+    A("push r23")                      \
197
+    A("push r24")                      \
198
+    A("push r25")                      \
199
+    A("push r26")                      \
200
+    A("push r27")                      \
201
+    A("push r30")                      \
202
+    A("push r31")                      \
203
+    A("clr r1")                        /* C runtime expects this register to be 0 */ \
204
+    A("call TIMER1_COMPA_vect_bottom") /* Call the bottom handler - No inlining allowed, otherwise registers used are not saved */   \
205
+    A("pop r31")                       \
206
+    A("pop r30")                       \
207
+    A("pop r27")                       \
208
+    A("pop r26")                       \
209
+    A("pop r25")                       \
210
+    A("pop r24")                       \
211
+    A("pop r23")                       \
212
+    A("pop r22")                       \
213
+    A("pop r21")                       \
214
+    A("pop r20")                       \
215
+    A("pop r19")                       \
216
+    A("pop r18")                       \
217
+    A("pop r1")                        \
218
+    A("pop r0")                        \
219
+    A("out 0x3C, r16")                 /* 1 Restore EIND register */ \
220
+    A("pop r16")                       /* 2 Get the original RAMPZ register value */ \
221
+    A("out 0x3B, r16")                 /* 1 Restore RAMPZ register to its original value */ \
222
+    A("pop r16")                       /* 2 Get the original TIMSK1 value but with stepper ISR disabled */ \
223
+    A("ori r16,%[msk1]")               /* 1 Reenable the stepper ISR */ \
224
+    A("cli")                           /* 1 Disable global interrupts - Reenabling Stepper ISR can reenter amd temperature can reenter, and we want that, if it happens, after this ISR has ended */ \
225
+    A("sts %[timsk1], r16")            /* 2 And restore the old value - This reenables the stepper ISR */ \
226
+    A("pop r16")                       /* 2 Get the temperature timer Interrupt mask register [TIMSK0] */ \
227
+    A("sts %[timsk0], r16")            /* 2 And restore the old value - This reenables the temperature ISR */ \
228
+    A("pop r16")                       /* 2 Get the old SREG value */ \
229
+    A("out __SREG__, r16")             /* 1 And restore the SREG value */ \
230
+    A("pop r16")                       /* 2 Restore R16 value */ \
231
+    A("reti")                          /* 4 Return from interrupt */ \
232
+    :                                   \
233
+    : [timsk0] "i" ((uint16_t)&TIMSK0), \
234
+      [timsk1] "i" ((uint16_t)&TIMSK1), \
235
+      [msk0] "M" ((uint8_t)(1<<OCIE0B)),\
236
+      [msk1] "M" ((uint8_t)(1<<OCIE1A)) \
237
+    : \
238
+  ); \
239
+} \
240
+void TIMER1_COMPA_vect_bottom(void)
241
+
242
+/* 14 cycles maximum latency */
243
+#define HAL_TEMP_TIMER_ISR \
244
+extern "C" void TIMER0_COMPB_vect (void) __attribute__ ((signal, naked, used, externally_visible)); \
245
+extern "C" void TIMER0_COMPB_vect_bottom(void)  asm ("TIMER0_COMPB_vect_bottom") __attribute__ ((used, externally_visible, noinline)); \
246
+void TIMER0_COMPB_vect (void) { \
247
+  __asm__ __volatile__ ( \
248
+    A("push r16")                       /* 2 Save R16 */ \
249
+    A("in r16, __SREG__")               /* 1 Get SREG */ \
250
+    A("push r16")                       /* 2 Save SREG into stack */ \
251
+    A("lds r16, %[timsk0]")             /* 2 Load into R0 the Temperature timer Interrupt mask register */ \
252
+    A("andi r16,~%[msk0]")              /* 1 Disable the temperature ISR */ \
253
+    A("sts %[timsk0], r16")             /* 2 And set the new value */ \
254
+    A("sei")                            /* 1 Enable global interrupts - It is safe, as the temperature ISR is disabled, so we cannot reenter it */    \
255
+    A("push r16")                       /* 2 Save TIMSK0 into stack */ \
256
+    A("in r16, 0x3B")                   /* 1 Get RAMPZ register */ \
257
+    A("push r16")                       /* 2 Save RAMPZ into stack */ \
258
+    A("in r16, 0x3C")                   /* 1 Get EIND register */ \
259
+    A("push r0")                        /* C runtime can modify all the following registers without restoring them */ \
260
+    A("push r1")                        \
261
+    A("push r18")                       \
262
+    A("push r19")                       \
263
+    A("push r20")                       \
264
+    A("push r21")                       \
265
+    A("push r22")                       \
266
+    A("push r23")                       \
267
+    A("push r24")                       \
268
+    A("push r25")                       \
269
+    A("push r26")                       \
270
+    A("push r27")                       \
271
+    A("push r30")                       \
272
+    A("push r31")                       \
273
+    A("clr r1")                         /* C runtime expects this register to be 0 */ \
274
+    A("call TIMER0_COMPB_vect_bottom")  /* Call the bottom handler - No inlining allowed, otherwise registers used are not saved */   \
275
+    A("pop r31")                        \
276
+    A("pop r30")                        \
277
+    A("pop r27")                        \
278
+    A("pop r26")                        \
279
+    A("pop r25")                        \
280
+    A("pop r24")                        \
281
+    A("pop r23")                        \
282
+    A("pop r22")                        \
283
+    A("pop r21")                        \
284
+    A("pop r20")                        \
285
+    A("pop r19")                        \
286
+    A("pop r18")                        \
287
+    A("pop r1")                         \
288
+    A("pop r0")                         \
289
+    A("out 0x3C, r16")                  /* 1 Restore EIND register */ \
290
+    A("pop r16")                        /* 2 Get the original RAMPZ register value */ \
291
+    A("out 0x3B, r16")                  /* 1 Restore RAMPZ register to its original value */ \
292
+    A("pop r16")                        /* 2 Get the original TIMSK0 value but with temperature ISR disabled */ \
293
+    A("ori r16,%[msk0]")                /* 1 Enable temperature ISR */ \
294
+    A("cli")                            /* 1 Disable global interrupts - We must do this, as we will reenable the temperature ISR, and we don´t want to reenter this handler until the current one is done */ \
295
+    A("sts %[timsk0], r16")             /* 2 And restore the old value */ \
296
+    A("pop r16")                        /* 2 Get the old SREG */ \
297
+    A("out __SREG__, r16")              /* 1 And restore the SREG value */ \
298
+    A("pop r16")                        /* 2 Restore R16 */ \
299
+    A("reti")                           /* 4 Return from interrupt */ \
300
+    :                                   \
301
+    : [timsk0] "i"((uint16_t)&TIMSK0),  \
302
+      [msk0] "M" ((uint8_t)(1<<OCIE0B)) \
303
+    : \
304
+  ); \
305
+} \
306
+void TIMER0_COMPB_vect_bottom(void)
183 307
 
184 308
 // ADC
185 309
 #ifdef DIDR2

+ 7
- 14
Marlin/src/HAL/HAL_AVR/endstop_interrupts.h 查看文件

@@ -24,7 +24,7 @@
24 24
  * Endstop Interrupts
25 25
  *
26 26
  * Without endstop interrupts the endstop pins must be polled continually in
27
- * the stepper-ISR via endstops.update(), most of the time finding no change.
27
+ * the temperature-ISR via endstops.update(), most of the time finding no change.
28 28
  * With this feature endstops.update() is called only when we know that at
29 29
  * least one endstop has changed state, saving valuable CPU cycles.
30 30
  *
@@ -40,17 +40,10 @@
40 40
 
41 41
 #include "../../core/macros.h"
42 42
 #include <stdint.h>
43
-
44
-volatile uint8_t e_hit = 0; // Different from 0 when the endstops should be tested in detail.
45
-                            // Must be reset to 0 by the test function when finished.
46
-
47
-// This is what is really done inside the interrupts.
48
-FORCE_INLINE void endstop_ISR_worker( void ) {
49
-  e_hit = 2; // Because the detection of a e-stop hit has a 1 step debouncer it has to be called at least twice.
50
-}
43
+#include "../../module/endstops.h"
51 44
 
52 45
 // One ISR for all EXT-Interrupts
53
-void endstop_ISR(void) { endstop_ISR_worker(); }
46
+void endstop_ISR(void) { endstops.check_possible_change(); }
54 47
 
55 48
 /**
56 49
  * Patch for pins_arduino.h (...\Arduino\hardware\arduino\avr\variants\mega\pins_arduino.h)
@@ -95,19 +88,19 @@ void pciSetup(const int8_t pin) {
95 88
 
96 89
 // Handlers for pin change interrupts
97 90
 #ifdef PCINT0_vect
98
-  ISR(PCINT0_vect) { endstop_ISR_worker(); }
91
+  ISR(PCINT0_vect) { endstop_ISR(); }
99 92
 #endif
100 93
 
101 94
 #ifdef PCINT1_vect
102
-  ISR(PCINT1_vect) { endstop_ISR_worker(); }
95
+  ISR(PCINT1_vect) { endstop_ISR(); }
103 96
 #endif
104 97
 
105 98
 #ifdef PCINT2_vect
106
-  ISR(PCINT2_vect) { endstop_ISR_worker(); }
99
+  ISR(PCINT2_vect) { endstop_ISR(); }
107 100
 #endif
108 101
 
109 102
 #ifdef PCINT3_vect
110
-  ISR(PCINT3_vect) { endstop_ISR_worker(); }
103
+  ISR(PCINT3_vect) { endstop_ISR(); }
111 104
 #endif
112 105
 
113 106
 void setup_endstop_interrupts( void ) {

+ 5
- 0
Marlin/src/HAL/HAL_DUE/DebugMonitor_Due.cpp 查看文件

@@ -46,6 +46,11 @@ static void TXBegin(void) {
46 46
   // Disable UART interrupt in NVIC
47 47
   NVIC_DisableIRQ( UART_IRQn );
48 48
 
49
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
50
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
51
+  __DSB();
52
+  __ISB();
53
+
49 54
   // Disable clock
50 55
   pmc_disable_periph_clk( ID_UART );
51 56
 

+ 21
- 6
Marlin/src/HAL/HAL_DUE/HAL_timers_Due.cpp 查看文件

@@ -99,6 +99,11 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
99 99
   // Disable interrupt, just in case it was already enabled
100 100
   NVIC_DisableIRQ(irq);
101 101
 
102
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
103
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
104
+  __DSB();
105
+  __ISB();
106
+
102 107
   // Disable timer interrupt
103 108
   tc->TC_CHANNEL[channel].TC_IDR = TC_IDR_CPCS;
104 109
 
@@ -126,18 +131,28 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
126 131
 }
127 132
 
128 133
 void HAL_timer_enable_interrupt(const uint8_t timer_num) {
129
-  const tTimerConfig * const pConfig = &TimerConfig[timer_num];
130
-  pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_IER = TC_IER_CPCS;
134
+  IRQn_Type irq = TimerConfig[timer_num].IRQ_Id;
135
+  NVIC_EnableIRQ(irq);
131 136
 }
132 137
 
133 138
 void HAL_timer_disable_interrupt(const uint8_t timer_num) {
134
-  const tTimerConfig * const pConfig = &TimerConfig[timer_num];
135
-  pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_IDR = TC_IDR_CPCS;
139
+  IRQn_Type irq = TimerConfig[timer_num].IRQ_Id;
140
+  NVIC_DisableIRQ(irq);
141
+
142
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
143
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
144
+  __DSB();
145
+  __ISB();
146
+}
147
+
148
+// missing from CMSIS: Check if interrupt is enabled or not
149
+static bool NVIC_GetEnabledIRQ(IRQn_Type IRQn) {
150
+  return (NVIC->ISER[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F))) != 0;
136 151
 }
137 152
 
138 153
 bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
139
-  const tTimerConfig * const pConfig = &TimerConfig[timer_num];
140
-  return (pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_IMR & TC_IMR_CPCS) != 0;
154
+  IRQn_Type irq = TimerConfig[timer_num].IRQ_Id;
155
+  return NVIC_GetEnabledIRQ(irq);
141 156
 }
142 157
 
143 158
 #endif // ARDUINO_ARCH_SAM

+ 0
- 2
Marlin/src/HAL/HAL_DUE/HAL_timers_Due.h 查看文件

@@ -118,8 +118,6 @@ void HAL_timer_enable_interrupt(const uint8_t timer_num);
118 118
 void HAL_timer_disable_interrupt(const uint8_t timer_num);
119 119
 bool HAL_timer_interrupt_enabled(const uint8_t timer_num);
120 120
 
121
-//void HAL_timer_isr_prologue(const uint8_t timer_num);
122
-
123 121
 FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) {
124 122
   const tTimerConfig * const pConfig = &TimerConfig[timer_num];
125 123
   // Reading the status register clears the interrupt flag

+ 10
- 0
Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp 查看文件

@@ -245,6 +245,11 @@
245 245
     // Disable UART interrupt in NVIC
246 246
     NVIC_DisableIRQ( HWUART_IRQ );
247 247
 
248
+    // We NEED memory barriers to ensure Interrupts are actually disabled!
249
+    // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
250
+    __DSB();
251
+    __ISB();
252
+
248 253
     // Disable clock
249 254
     pmc_disable_periph_clk( HWUART_IRQ_ID );
250 255
 
@@ -290,6 +295,11 @@
290 295
     // Disable UART interrupt in NVIC
291 296
     NVIC_DisableIRQ( HWUART_IRQ );
292 297
 
298
+    // We NEED memory barriers to ensure Interrupts are actually disabled!
299
+    // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
300
+    __DSB();
301
+    __ISB();
302
+
293 303
     pmc_disable_periph_clk( HWUART_IRQ_ID );
294 304
   }
295 305
 

+ 3
- 9
Marlin/src/HAL/HAL_DUE/endstop_interrupts.h 查看文件

@@ -24,7 +24,7 @@
24 24
  * Endstop Interrupts
25 25
  *
26 26
  * Without endstop interrupts the endstop pins must be polled continually in
27
- * the stepper-ISR via endstops.update(), most of the time finding no change.
27
+ * the temperature-ISR via endstops.update(), most of the time finding no change.
28 28
  * With this feature endstops.update() is called only when we know that at
29 29
  * least one endstop has changed state, saving valuable CPU cycles.
30 30
  *
@@ -37,16 +37,10 @@
37 37
 #ifndef _ENDSTOP_INTERRUPTS_H_
38 38
 #define _ENDSTOP_INTERRUPTS_H_
39 39
 
40
-volatile uint8_t e_hit = 0; // Different from 0 when the endstops should be tested in detail.
41
-                            // Must be reset to 0 by the test function when finished.
42
-
43
-// This is what is really done inside the interrupts.
44
-FORCE_INLINE void endstop_ISR_worker( void ) {
45
-  e_hit = 2; // Because the detection of a e-stop hit has a 1 step debouncer it has to be called at least twice.
46
-}
40
+#include "../../module/endstops.h"
47 41
 
48 42
 // One ISR for all EXT-Interrupts
49
-void endstop_ISR(void) { endstop_ISR_worker(); }
43
+void endstop_ISR(void) { endstops.check_possible_change(); }
50 44
 
51 45
 /**
52 46
  *  Endstop interrupts for Due based targets.

+ 5
- 0
Marlin/src/HAL/HAL_DUE/watchdog_Due.cpp 查看文件

@@ -68,6 +68,11 @@ void watchdogSetup(void) {
68 68
       // Disable WDT interrupt (just in case, to avoid triggering it!)
69 69
       NVIC_DisableIRQ(WDT_IRQn);
70 70
 
71
+      // We NEED memory barriers to ensure Interrupts are actually disabled!
72
+      // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
73
+      __DSB();
74
+      __ISB();
75
+
71 76
       // Initialize WDT with the given parameters
72 77
       WDT_Enable(WDT, value);
73 78
 

+ 13
- 40
Marlin/src/HAL/HAL_LPC1768/HAL_timers.cpp 查看文件

@@ -23,7 +23,7 @@
23 23
 /**
24 24
  * Description:
25 25
  *
26
- * For TARGET_LPC1768
26
+ * Timers for LPC1768
27 27
  */
28 28
 
29 29
 #ifdef TARGET_LPC1768
@@ -32,61 +32,34 @@
32 32
 #include "HAL_timers.h"
33 33
 
34 34
 void HAL_timer_init(void) {
35
-  SBI(LPC_SC->PCONP, 1);  // power on timer0
35
+  SBI(LPC_SC->PCONP, SBIT_TIMER0);  // Power ON Timer 0
36 36
   LPC_TIM0->PR = (HAL_TIMER_RATE) / (HAL_STEPPER_TIMER_RATE) - 1; // Use prescaler to set frequency if needed
37 37
 
38
-  SBI(LPC_SC->PCONP, 2);  // power on timer1
38
+  SBI(LPC_SC->PCONP, SBIT_TIMER1);  // Power ON Timer 1
39 39
   LPC_TIM1->PR = (HAL_TIMER_RATE) / 1000000 - 1;
40 40
 }
41 41
 
42 42
 void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
43 43
   switch (timer_num) {
44 44
     case 0:
45
-      LPC_TIM0->MCR = 3;              // Match on MR0, reset on MR0
45
+      LPC_TIM0->MCR = _BV(SBIT_MR0I) | _BV(SBIT_MR0R); // Match on MR0, reset on MR0, interrupts when NVIC enables them
46 46
       LPC_TIM0->MR0 = uint32_t(HAL_STEPPER_TIMER_RATE) / frequency; // Match value (period) to set frequency
47
-      LPC_TIM0->TCR = _BV(0);       // enable
48
-      break;
49
-    case 1:
50
-      LPC_TIM1->MCR = 3;
51
-      LPC_TIM1->MR0 = uint32_t(HAL_TEMP_TIMER_RATE) / frequency;
52
-      LPC_TIM1->TCR = _BV(0);
53
-      break;
54
-    default: break;
55
-  }
56
-}
47
+      LPC_TIM0->TCR = _BV(SBIT_CNTEN); // Counter Enable
57 48
 
58
-void HAL_timer_enable_interrupt(const uint8_t timer_num) {
59
-  switch (timer_num) {
60
-    case 0:
61
-      NVIC_EnableIRQ(TIMER0_IRQn); // Enable interrupt handler
62 49
       NVIC_SetPriority(TIMER0_IRQn, NVIC_EncodePriority(0, 1, 0));
50
+      NVIC_EnableIRQ(TIMER0_IRQn);
63 51
       break;
52
+
64 53
     case 1:
65
-      NVIC_EnableIRQ(TIMER1_IRQn);
54
+      LPC_TIM1->MCR = _BV(SBIT_MR0I) | _BV(SBIT_MR0R); // Match on MR0, reset on MR0, interrupts when NVIC enables them
55
+      LPC_TIM1->MR0 = uint32_t(HAL_TEMP_TIMER_RATE) / frequency;
56
+      LPC_TIM1->TCR = _BV(SBIT_CNTEN); // Counter Enable
57
+
66 58
       NVIC_SetPriority(TIMER1_IRQn, NVIC_EncodePriority(0, 2, 0));
59
+      NVIC_EnableIRQ(TIMER1_IRQn);
67 60
       break;
68
-  }
69
-}
70
-
71
-void HAL_timer_disable_interrupt(const uint8_t timer_num) {
72
-  switch (timer_num) {
73
-    case 0: NVIC_DisableIRQ(TIMER0_IRQn); break; // disable interrupt handler
74
-    case 1: NVIC_DisableIRQ(TIMER1_IRQn); break;
75
-  }
76
-}
77 61
 
78
-bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
79
-  switch (timer_num) {
80
-    case 0: return NVIC_GetActive(TIMER0_IRQn);
81
-    case 1: return NVIC_GetActive(TIMER1_IRQn);
82
-  }
83
-  return false;
84
-}
85
-
86
-void HAL_timer_isr_prologue(const uint8_t timer_num) {
87
-  switch (timer_num) {
88
-    case 0: SBI(LPC_TIM0->IR, 0); break; // Clear the Interrupt
89
-    case 1: SBI(LPC_TIM1->IR, 0); break;
62
+    default: break;
90 63
   }
91 64
 }
92 65
 

+ 78
- 36
Marlin/src/HAL/HAL_LPC1768/HAL_timers.h 查看文件

@@ -34,18 +34,42 @@
34 34
 
35 35
 #include <stdint.h>
36 36
 
37
+#include "../../core/macros.h"
38
+
39
+#define SBIT_TIMER0 1
40
+#define SBIT_TIMER1 2
41
+
42
+#define SBIT_CNTEN 0
43
+
44
+#define SBIT_MR0I  0 // Timer 0 Interrupt when TC matches MR0
45
+#define SBIT_MR0R  1 // Timer 0 Reset TC on Match
46
+#define SBIT_MR0S  2 // Timer 0 Stop TC and PC on Match
47
+#define SBIT_MR1I  3
48
+#define SBIT_MR1R  4
49
+#define SBIT_MR1S  5
50
+#define SBIT_MR2I  6
51
+#define SBIT_MR2R  7
52
+#define SBIT_MR2S  8
53
+#define SBIT_MR3I  9
54
+#define SBIT_MR3R 10
55
+#define SBIT_MR3S 11
56
+
37 57
 // --------------------------------------------------------------------------
38 58
 // Defines
39 59
 // --------------------------------------------------------------------------
40 60
 
41
-#define FORCE_INLINE __attribute__((always_inline)) inline
61
+#define _HAL_TIMER(T) _CAT(LPC_TIM, T)
62
+#define _HAL_TIMER_IRQ(T) TIMER##T##_IRQn
63
+#define __HAL_TIMER_ISR(T) extern "C" void TIMER##T##_IRQHandler(void)
64
+#define _HAL_TIMER_ISR(T)  __HAL_TIMER_ISR(T)
42 65
 
43 66
 typedef uint32_t hal_timer_t;
44 67
 #define HAL_TIMER_TYPE_MAX 0xFFFFFFFF
45 68
 
46
-#define STEP_TIMER_NUM 0  // index of timer to use for stepper
47
-#define TEMP_TIMER_NUM 1  // index of timer to use for temperature
69
+#define STEP_TIMER_NUM 0  // Timer Index for Stepper
70
+#define TEMP_TIMER_NUM 1  // Timer Index for Temperature
48 71
 #define PULSE_TIMER_NUM STEP_TIMER_NUM
72
+#define PWM_TIMER_NUM 3   // Timer Index for PWM
49 73
 
50 74
 #define HAL_TIMER_RATE         ((SystemCoreClock) / 4)  // frequency of timers peripherals
51 75
 #define HAL_STEPPER_TIMER_RATE HAL_TIMER_RATE   // frequency of stepper timer (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE)
@@ -66,21 +90,12 @@ typedef uint32_t hal_timer_t;
66 90
 #define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(TEMP_TIMER_NUM)
67 91
 #define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(TEMP_TIMER_NUM)
68 92
 
69
-#define HAL_STEP_TIMER_ISR  extern "C" void TIMER0_IRQHandler(void)
70
-#define HAL_TEMP_TIMER_ISR  extern "C" void TIMER1_IRQHandler(void)
71
-
72
-// PWM timer
73
-#define HAL_PWM_TIMER      LPC_TIM3
74
-#define HAL_PWM_TIMER_ISR  extern "C" void TIMER3_IRQHandler(void)
75
-#define HAL_PWM_TIMER_IRQn TIMER3_IRQn
93
+#define HAL_STEP_TIMER_ISR _HAL_TIMER_ISR(STEP_TIMER_NUM)
94
+#define HAL_TEMP_TIMER_ISR _HAL_TIMER_ISR(TEMP_TIMER_NUM)
76 95
 
77
-// --------------------------------------------------------------------------
78
-// Types
79
-// --------------------------------------------------------------------------
80
-
81
-// --------------------------------------------------------------------------
82
-// Public Variables
83
-// --------------------------------------------------------------------------
96
+// Timer references by index
97
+#define STEP_TIMER _HAL_TIMER(STEP_TIMER_NUM)
98
+#define TEMP_TIMER _HAL_TIMER(TEMP_TIMER_NUM)
84 99
 
85 100
 // --------------------------------------------------------------------------
86 101
 // Public functions
@@ -90,31 +105,23 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency);
90 105
 
91 106
 FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_num, const hal_timer_t compare) {
92 107
   switch (timer_num) {
93
-    case 0:
94
-      LPC_TIM0->MR0 = compare;
95
-      if (LPC_TIM0->TC > compare)
96
-        LPC_TIM0->TC = compare - 5; // generate an immediate stepper ISR
97
-      break;
98
-    case 1:
99
-      LPC_TIM1->MR0 = compare;
100
-      if (LPC_TIM1->TC > compare)
101
-        LPC_TIM1->TC = compare - 5; // make sure we don't have one extra long period
102
-      break;
108
+    case 0: STEP_TIMER->MR0 = compare; break; // Stepper Timer Match Register 0
109
+    case 1: TEMP_TIMER->MR0 = compare; break; //    Temp Timer Match Register 0
103 110
   }
104 111
 }
105 112
 
106 113
 FORCE_INLINE static hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {
107 114
   switch (timer_num) {
108
-    case 0: return LPC_TIM0->MR0;
109
-    case 1: return LPC_TIM1->MR0;
115
+    case 0: return STEP_TIMER->MR0; // Stepper Timer Match Register 0
116
+    case 1: return TEMP_TIMER->MR0; //    Temp Timer Match Register 0
110 117
   }
111 118
   return 0;
112 119
 }
113 120
 
114 121
 FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_num) {
115 122
   switch (timer_num) {
116
-    case 0: return LPC_TIM0->TC;
117
-    case 1: return LPC_TIM1->TC;
123
+    case 0: return STEP_TIMER->TC; // Stepper Timer Count
124
+    case 1: return TEMP_TIMER->TC; //    Temp Timer Count
118 125
   }
119 126
   return 0;
120 127
 }
@@ -124,10 +131,45 @@ FORCE_INLINE static void HAL_timer_restrain(const uint8_t timer_num, const uint1
124 131
   if (HAL_timer_get_compare(timer_num) < mincmp) HAL_timer_set_compare(timer_num, mincmp);
125 132
 }
126 133
 
127
-void HAL_timer_enable_interrupt(const uint8_t timer_num);
128
-void HAL_timer_disable_interrupt(const uint8_t timer_num);
129
-bool HAL_timer_interrupt_enabled(const uint8_t timer_num);
130
-void HAL_timer_isr_prologue(const uint8_t timer_num);
134
+FORCE_INLINE static void HAL_timer_enable_interrupt(const uint8_t timer_num) {
135
+  switch (timer_num) {
136
+    case 0: NVIC_EnableIRQ(TIMER0_IRQn); // Enable interrupt handler
137
+    case 1: NVIC_EnableIRQ(TIMER1_IRQn); // Enable interrupt handler
138
+  }
139
+}
140
+
141
+FORCE_INLINE static void HAL_timer_disable_interrupt(const uint8_t timer_num) {
142
+  switch (timer_num) {
143
+    case 0: NVIC_DisableIRQ(TIMER0_IRQn); // Disable interrupt handler
144
+    case 1: NVIC_DisableIRQ(TIMER1_IRQn); // Disable interrupt handler
145
+  }
146
+
147
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
148
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
149
+  __DSB();
150
+  __ISB();
151
+}
152
+
153
+// This function is missing from CMSIS
154
+FORCE_INLINE static bool NVIC_GetEnableIRQ(IRQn_Type IRQn) {
155
+  return (NVIC->ISER[((uint32_t)IRQn) >> 5] & (1 << ((uint32_t)IRQn) & 0x1F)) != 0;
156
+}
157
+
158
+FORCE_INLINE static bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
159
+  switch (timer_num) {
160
+    case 0: return NVIC_GetEnableIRQ(TIMER0_IRQn); // Check if interrupt is enabled or not
161
+    case 1: return NVIC_GetEnableIRQ(TIMER1_IRQn); // Check if interrupt is enabled or not
162
+  }
163
+  return false;
164
+}
165
+
166
+FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) {
167
+  switch (timer_num) {
168
+    case 0: SBI(STEP_TIMER->IR, SBIT_CNTEN); break;
169
+    case 1: SBI(TEMP_TIMER->IR, SBIT_CNTEN); break;
170
+  }
171
+}
172
+
131 173
 #define HAL_timer_isr_epilogue(TIMER_NUM)
132 174
 
133
-#endif // _HAL_TIMERS_DUE_H
175
+#endif // _HAL_TIMERS_H

+ 24
- 1
Marlin/src/HAL/HAL_LPC1768/LPC1768_PWM.cpp 查看文件

@@ -78,12 +78,14 @@
78 78
 
79 79
 #define NUM_ISR_PWMS 20
80 80
 
81
+#define HAL_PWM_TIMER      LPC_TIM3
82
+#define HAL_PWM_TIMER_ISR  extern "C" void TIMER3_IRQHandler(void)
83
+#define HAL_PWM_TIMER_IRQn TIMER3_IRQn
81 84
 
82 85
 #define LPC_PORT_OFFSET         (0x0020)
83 86
 #define LPC_PIN(pin)            (1UL << pin)
84 87
 #define LPC_GPIO(port)          ((volatile LPC_GPIO_TypeDef *)(LPC_GPIO0_BASE + LPC_PORT_OFFSET * port))
85 88
 
86
-
87 89
 typedef struct {            // holds all data needed to control/init one of the PWM channels
88 90
   bool                active_flag;    // THIS TABLE ENTRY IS ACTIVELY TOGGLING A PIN
89 91
   pin_t               pin;
@@ -256,6 +258,11 @@ bool LPC1768_PWM_attach_pin(pin_t pin, uint32_t min /* = 1 */, uint32_t max /* =
256 258
                                  // OK to update the active table because the
257 259
                                  // ISR doesn't use any of the changed items
258 260
 
261
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
262
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
263
+  __DSB();
264
+  __ISB();
265
+
259 266
   if (ISR_table_update) //use work table if that's the newest
260 267
     temp_table = work_table;
261 268
   else
@@ -340,6 +347,11 @@ bool LPC1768_PWM_detach_pin(pin_t pin) {
340 347
 ////  interrupt controlled PWM code
341 348
   NVIC_DisableIRQ(HAL_PWM_TIMER_IRQn);
342 349
 
350
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
351
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
352
+  __DSB();
353
+  __ISB();
354
+
343 355
   if (ISR_table_update) {
344 356
     ISR_table_update = false;    // don't update yet - have another update to do
345 357
     NVIC_EnableIRQ(HAL_PWM_TIMER_IRQn);  // re-enable PWM interrupts
@@ -426,6 +438,12 @@ bool LPC1768_PWM_write(pin_t pin, uint32_t value) {
426 438
 
427 439
 ////  interrupt controlled PWM code
428 440
   NVIC_DisableIRQ(HAL_PWM_TIMER_IRQn);
441
+
442
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
443
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
444
+  __DSB();
445
+  __ISB();
446
+
429 447
   if (!ISR_table_update)   // use the most up to date table
430 448
     COPY_ACTIVE_TABLE;  // copy active table into work table
431 449
 
@@ -454,6 +472,11 @@ bool useable_hardware_PWM(pin_t pin) {
454 472
 
455 473
   NVIC_DisableIRQ(HAL_PWM_TIMER_IRQn);
456 474
 
475
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
476
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
477
+  __DSB();
478
+  __ISB();
479
+
457 480
   bool return_flag = false;
458 481
   for (uint8_t i = 0; i < NUM_ISR_PWMS; i++)         // see if it's already setup
459 482
     if (active_table[i].pin == pin) return_flag = true;

+ 3
- 9
Marlin/src/HAL/HAL_LPC1768/endstop_interrupts.h 查看文件

@@ -24,7 +24,7 @@
24 24
  * Endstop Interrupts
25 25
  *
26 26
  * Without endstop interrupts the endstop pins must be polled continually in
27
- * the stepper-ISR via endstops.update(), most of the time finding no change.
27
+ * the temperature-ISR via endstops.update(), most of the time finding no change.
28 28
  * With this feature endstops.update() is called only when we know that at
29 29
  * least one endstop has changed state, saving valuable CPU cycles.
30 30
  *
@@ -40,16 +40,10 @@
40 40
 //Currently this is untested and broken
41 41
 #error "Please disable Endstop Interrupts LPC176x is currently an unsupported platform"
42 42
 
43
-volatile uint8_t e_hit = 0; // Different from 0 when the endstops should be tested in detail.
44
-                            // Must be reset to 0 by the test function when finished.
45
-
46
-// This is what is really done inside the interrupts.
47
-FORCE_INLINE void endstop_ISR_worker( void ) {
48
-  e_hit = 2; // Because the detection of a e-stop hit has a 1 step debouncer it has to be called at least twice.
49
-}
43
+#include "../../module/endstops.h"
50 44
 
51 45
 // One ISR for all EXT-Interrupts
52
-void endstop_ISR(void) { endstop_ISR_worker(); }
46
+void endstop_ISR(void) { endstops.check_possible_change(); }
53 47
 
54 48
 void setup_endstop_interrupts(void) {
55 49
   #if HAS_X_MAX

+ 3
- 9
Marlin/src/HAL/HAL_STM32F1/endstop_interrupts.h 查看文件

@@ -36,7 +36,7 @@
36 36
  * Endstop Interrupts
37 37
  *
38 38
  * Without endstop interrupts the endstop pins must be polled continually in
39
- * the stepper-ISR via endstops.update(), most of the time finding no change.
39
+ * the temperature-ISR via endstops.update(), most of the time finding no change.
40 40
  * With this feature endstops.update() is called only when we know that at
41 41
  * least one endstop has changed state, saving valuable CPU cycles.
42 42
  *
@@ -49,16 +49,10 @@
49 49
 #ifndef _ENDSTOP_INTERRUPTS_H_
50 50
 #define _ENDSTOP_INTERRUPTS_H_
51 51
 
52
-volatile uint8_t e_hit = 0; // Different from 0 when the endstops should be tested in detail.
53
-                            // Must be reset to 0 by the test function when finished.
54
-
55
-// This is what is really done inside the interrupts.
56
-FORCE_INLINE void endstop_ISR_worker( void ) {
57
-  e_hit = 2; // Because the detection of a e-stop hit has a 1 step debouncer it has to be called at least twice.
58
-}
52
+#include "../../module/endstops.h"
59 53
 
60 54
 // One ISR for all EXT-Interrupts
61
-void endstop_ISR(void) { endstop_ISR_worker(); }
55
+void endstop_ISR(void) { endstops.check_possible_change(); }
62 56
 
63 57
 void setup_endstop_interrupts(void) {
64 58
   #if HAS_X_MAX

+ 5
- 0
Marlin/src/HAL/HAL_STM32F4/HAL_timers_STM32F4.cpp 查看文件

@@ -123,6 +123,11 @@ void HAL_timer_enable_interrupt(const uint8_t timer_num) {
123 123
 
124 124
 void HAL_timer_disable_interrupt(const uint8_t timer_num) {
125 125
   HAL_NVIC_DisableIRQ(timerConfig[timer_num].IRQ_Id);
126
+
127
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
128
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
129
+  __DSB();
130
+  __ISB();
126 131
 }
127 132
 
128 133
 hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {

+ 2
- 8
Marlin/src/HAL/HAL_STM32F4/endstop_interrupts.h 查看文件

@@ -24,16 +24,10 @@
24 24
 #ifndef _ENDSTOP_INTERRUPTS_H_
25 25
 #define _ENDSTOP_INTERRUPTS_H_
26 26
 
27
-volatile uint8_t e_hit = 0; // Different from 0 when the endstops should be tested in detail.
28
-                            // Must be reset to 0 by the test function when finished.
29
-
30
-// This is what is really done inside the interrupts.
31
-FORCE_INLINE void endstop_ISR_worker( void ) {
32
-  e_hit = 2; // Because the detection of a e-stop hit has a 1 step debouncer it has to be called at least twice.
33
-}
27
+#include "../../module/endstops.h"
34 28
 
35 29
 // One ISR for all EXT-Interrupts
36
-void endstop_ISR(void) { endstop_ISR_worker(); }
30
+void endstop_ISR(void) { endstops.check_possible_change(); }
37 31
 
38 32
 void setup_endstop_interrupts(void) {
39 33
   #if HAS_X_MAX

+ 5
- 0
Marlin/src/HAL/HAL_STM32F7/HAL_timers_STM32F7.cpp 查看文件

@@ -127,6 +127,11 @@ void HAL_timer_enable_interrupt(const uint8_t timer_num) {
127 127
 
128 128
 void HAL_timer_disable_interrupt(const uint8_t timer_num) {
129 129
   HAL_NVIC_DisableIRQ(timerConfig[timer_num].IRQ_Id);
130
+
131
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
132
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
133
+  __DSB();
134
+  __ISB();
130 135
 }
131 136
 
132 137
 hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {

+ 2
- 8
Marlin/src/HAL/HAL_STM32F7/endstop_interrupts.h 查看文件

@@ -26,16 +26,10 @@
26 26
 #ifndef _ENDSTOP_INTERRUPTS_H_
27 27
 #define _ENDSTOP_INTERRUPTS_H_
28 28
 
29
-volatile uint8_t e_hit = 0; // Different from 0 when the endstops should be tested in detail.
30
-                            // Must be reset to 0 by the test function when finished.
31
-
32
-// This is what is really done inside the interrupts.
33
-FORCE_INLINE void endstop_ISR_worker( void ) {
34
-  e_hit = 2; // Because the detection of a e-stop hit has a 1 step debouncer it has to be called at least twice.
35
-}
29
+#include "../../module/endstops.h"
36 30
 
37 31
 // One ISR for all EXT-Interrupts
38
-void endstop_ISR(void) { endstop_ISR_worker(); }
32
+void endstop_ISR(void) { endstops.check_possible_change(); }
39 33
 
40 34
 void setup_endstop_interrupts(void) {
41 35
   #if HAS_X_MAX

+ 21
- 0
Marlin/src/HAL/HAL_TEENSY35_36/HAL_timers_Teensy.cpp 查看文件

@@ -29,6 +29,22 @@
29 29
 #include "HAL.h"
30 30
 #include "HAL_timers_Teensy.h"
31 31
 
32
+/** \brief Instruction Synchronization Barrier
33
+  Instruction Synchronization Barrier flushes the pipeline in the processor,
34
+  so that all instructions following the ISB are fetched from cache or
35
+  memory, after the instruction has been completed.
36
+*/
37
+FORCE_INLINE static void __ISB(void) {
38
+  __asm__ __volatile__("isb 0xF":::"memory");
39
+}
40
+
41
+/** \brief Data Synchronization Barrier
42
+  This function acts as a special kind of Data Memory Barrier.
43
+  It completes when all explicit memory accesses before this instruction complete.
44
+*/
45
+FORCE_INLINE static void __DSB(void) {
46
+  __asm__ __volatile__("dsb 0xF":::"memory");
47
+}
32 48
 
33 49
 void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
34 50
   switch (timer_num) {
@@ -65,6 +81,11 @@ void HAL_timer_disable_interrupt(const uint8_t timer_num) {
65 81
     case 0: NVIC_DISABLE_IRQ(IRQ_FTM0); break;
66 82
     case 1: NVIC_DISABLE_IRQ(IRQ_FTM1); break;
67 83
   }
84
+
85
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
86
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
87
+  __DSB();
88
+  __ISB();
68 89
 }
69 90
 
70 91
 bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {

+ 3
- 9
Marlin/src/HAL/HAL_TEENSY35_36/endstop_interrupts.h 查看文件

@@ -24,7 +24,7 @@
24 24
  * Endstop Interrupts
25 25
  *
26 26
  * Without endstop interrupts the endstop pins must be polled continually in
27
- * the stepper-ISR via endstops.update(), most of the time finding no change.
27
+ * the temperature-ISR via endstops.update(), most of the time finding no change.
28 28
  * With this feature endstops.update() is called only when we know that at
29 29
  * least one endstop has changed state, saving valuable CPU cycles.
30 30
  *
@@ -37,16 +37,10 @@
37 37
 #ifndef _ENDSTOP_INTERRUPTS_H_
38 38
 #define _ENDSTOP_INTERRUPTS_H_
39 39
 
40
-volatile uint8_t e_hit = 0; // Different from 0 when the endstops should be tested in detail.
41
-                            // Must be reset to 0 by the test function when finished.
42
-
43
-// This is what is really done inside the interrupts.
44
-FORCE_INLINE void endstop_ISR_worker( void ) {
45
-  e_hit = 2; // Because the detection of a e-stop hit has a 1 step debouncer it has to be called at least twice.
46
-}
40
+#include "../../module/endstops.h"
47 41
 
48 42
 // One ISR for all EXT-Interrupts
49
-void endstop_ISR(void) { endstop_ISR_worker(); }
43
+void endstop_ISR(void) { endstops.check_possible_change(); }
50 44
 
51 45
 /**
52 46
  *  Endstop interrupts for Due based targets.

+ 4
- 10
Marlin/src/Marlin.cpp 查看文件

@@ -95,10 +95,6 @@
95 95
   #include "feature/I2CPositionEncoder.h"
96 96
 #endif
97 97
 
98
-#if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
99
-  #include HAL_PATH(HAL, endstop_interrupts.h)
100
-#endif
101
-
102 98
 #if HAS_TRINAMIC
103 99
   #include "feature/tmc_util.h"
104 100
 #endif
@@ -269,7 +265,7 @@ bool pin_is_protected(const pin_t pin) {
269 265
 }
270 266
 
271 267
 void quickstop_stepper() {
272
-  stepper.quick_stop();
268
+  planner.quick_stop();
273 269
   planner.synchronize();
274 270
   set_current_from_steppers_for_axis(ALL_AXES);
275 271
   SYNC_PLAN_POSITION_KINEMATIC();
@@ -748,7 +744,9 @@ void setup() {
748 744
 
749 745
   print_job_timer.init();   // Initial setup of print job timer
750 746
 
751
-  stepper.init();    // Initialize stepper, this enables interrupts!
747
+  endstops.init();          // Init endstops and pullups
748
+
749
+  stepper.init();           // Init stepper. This enables interrupts!
752 750
 
753 751
   #if HAS_SERVOS
754 752
     servo_init();
@@ -860,10 +858,6 @@ void setup() {
860 858
     i2c.onRequest(i2c_on_request);
861 859
   #endif
862 860
 
863
-  #if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
864
-    setup_endstop_interrupts();
865
-  #endif
866
-
867 861
   #if DO_SWITCH_EXTRUDER
868 862
     move_extruder_servo(0);  // Initialize extruder servo
869 863
   #endif

+ 0
- 4
Marlin/src/feature/Max7219_Debug_LEDs.cpp 查看文件

@@ -73,7 +73,6 @@ static uint8_t LEDs[8] = { 0 };
73 73
 #endif
74 74
 
75 75
 void Max7219_PutByte(uint8_t data) {
76
-  CRITICAL_SECTION_START;
77 76
   for (uint8_t i = 8; i--;) {
78 77
     SIG_DELAY();
79 78
     WRITE(MAX7219_CLK_PIN, LOW);       // tick
@@ -84,12 +83,10 @@ void Max7219_PutByte(uint8_t data) {
84 83
     SIG_DELAY();
85 84
     data <<= 1;
86 85
   }
87
-  CRITICAL_SECTION_END;
88 86
 }
89 87
 
90 88
 void Max7219(const uint8_t reg, const uint8_t data) {
91 89
   SIG_DELAY();
92
-  CRITICAL_SECTION_START;
93 90
   WRITE(MAX7219_LOAD_PIN, LOW);  // begin
94 91
   SIG_DELAY();
95 92
   Max7219_PutByte(reg);          // specify register
@@ -99,7 +96,6 @@ void Max7219(const uint8_t reg, const uint8_t data) {
99 96
   WRITE(MAX7219_LOAD_PIN, LOW);  // and tell the chip to load the data
100 97
   SIG_DELAY();
101 98
   WRITE(MAX7219_LOAD_PIN, HIGH);
102
-  CRITICAL_SECTION_END;
103 99
   SIG_DELAY();
104 100
 }
105 101
 

+ 6
- 3
Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp 查看文件

@@ -262,7 +262,8 @@
262 262
             z_position = end[Z_AXIS];
263 263
           }
264 264
 
265
-          planner.buffer_segment(rx, ry, z_position + z0, e_position, feed_rate, extruder);
265
+          if (!planner.buffer_segment(rx, ry, z_position + z0, e_position, feed_rate, extruder))
266
+            break;
266 267
         } //else printf("FIRST MOVE PRUNED  ");
267 268
       }
268 269
 
@@ -319,7 +320,8 @@
319 320
           e_position = end[E_AXIS];
320 321
           z_position = end[Z_AXIS];
321 322
         }
322
-        planner.buffer_segment(rx, next_mesh_line_y, z_position + z0, e_position, feed_rate, extruder);
323
+        if (!planner.buffer_segment(rx, next_mesh_line_y, z_position + z0, e_position, feed_rate, extruder))
324
+          break;
323 325
         current_yi += dyi;
324 326
         yi_cnt--;
325 327
       }
@@ -342,7 +344,8 @@
342 344
           z_position = end[Z_AXIS];
343 345
         }
344 346
 
345
-        planner.buffer_segment(next_mesh_line_x, ry, z_position + z0, e_position, feed_rate, extruder);
347
+        if (!planner.buffer_segment(next_mesh_line_x, ry, z_position + z0, e_position, feed_rate, extruder))
348
+          break;
346 349
         current_xi += dxi;
347 350
         xi_cnt--;
348 351
       }

+ 1
- 1
Marlin/src/gcode/config/M540.cpp 查看文件

@@ -33,7 +33,7 @@
33 33
 void GcodeSuite::M540() {
34 34
 
35 35
   if (parser.seen('S'))
36
-    stepper.abort_on_endstop_hit = parser.value_bool();
36
+    planner.abort_on_endstop_hit = parser.value_bool();
37 37
 
38 38
 }
39 39
 

+ 1
- 1
Marlin/src/gcode/control/M17_M18_M84.cpp 查看文件

@@ -47,7 +47,7 @@ void GcodeSuite::M18_M84() {
47 47
   else {
48 48
     bool all_axis = !(parser.seen('X') || parser.seen('Y') || parser.seen('Z') || parser.seen('E'));
49 49
     if (all_axis) {
50
-      stepper.finish_and_disable();
50
+      planner.finish_and_disable();
51 51
     }
52 52
     else {
53 53
       planner.synchronize();

+ 1
- 1
Marlin/src/gcode/control/M80_M81.cpp 查看文件

@@ -95,7 +95,7 @@
95 95
  */
96 96
 void GcodeSuite::M81() {
97 97
   thermalManager.disable_all_heaters();
98
-  stepper.finish_and_disable();
98
+  planner.finish_and_disable();
99 99
 
100 100
   #if FAN_COUNT > 0
101 101
     for (uint8_t i = 0; i < FAN_COUNT; i++) fanSpeeds[i] = 0;

+ 6
- 3
Marlin/src/gcode/motion/G2_G3.cpp 查看文件

@@ -197,14 +197,17 @@ void plan_arc(
197 197
       // i.e., Complete the angular vector in the given time.
198 198
       inverse_kinematics(raw);
199 199
       ADJUST_DELTA(raw);
200
-      planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], raw[Z_AXIS], raw[E_AXIS], HYPOT(delta[A_AXIS] - oldA, delta[B_AXIS] - oldB) * inverse_secs, active_extruder);
200
+      if (!planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], raw[Z_AXIS], raw[E_AXIS], HYPOT(delta[A_AXIS] - oldA, delta[B_AXIS] - oldB) * inverse_secs, active_extruder))
201
+        break;
201 202
       oldA = delta[A_AXIS]; oldB = delta[B_AXIS];
202 203
     #elif HAS_UBL_AND_CURVES
203 204
       float pos[XYZ] = { raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS] };
204 205
       planner.apply_leveling(pos);
205
-      planner.buffer_segment(pos[X_AXIS], pos[Y_AXIS], pos[Z_AXIS], raw[E_AXIS], fr_mm_s, active_extruder);
206
+      if (!planner.buffer_segment(pos[X_AXIS], pos[Y_AXIS], pos[Z_AXIS], raw[E_AXIS], fr_mm_s, active_extruder))
207
+        break;
206 208
     #else
207
-      planner.buffer_line_kinematic(raw, fr_mm_s, active_extruder);
209
+      if (!planner.buffer_line_kinematic(raw, fr_mm_s, active_extruder))
210
+        break;
208 211
     #endif
209 212
   }
210 213
 

+ 2
- 4
Marlin/src/lcd/ultralcd.cpp 查看文件

@@ -2421,12 +2421,10 @@ void lcd_quick_feedback(const bool clear_buttons) {
2421 2421
 
2422 2422
     void _lcd_do_nothing() {}
2423 2423
     void _lcd_hard_stop() {
2424
-      stepper.quick_stop();
2425 2424
       const screenFunc_t old_screen = currentScreen;
2426 2425
       currentScreen = _lcd_do_nothing;
2427
-      while (planner.movesplanned()) idle();
2426
+      planner.quick_stop();
2428 2427
       currentScreen = old_screen;
2429
-      stepper.cleaning_buffer_counter = 0;
2430 2428
       set_current_from_steppers_for_axis(ALL_AXES);
2431 2429
       sync_plan_position();
2432 2430
     }
@@ -3856,7 +3854,7 @@ void lcd_quick_feedback(const bool clear_buttons) {
3856 3854
 
3857 3855
     // M540 S - Abort on endstop hit when SD printing
3858 3856
     #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
3859
-      MENU_ITEM_EDIT(bool, MSG_ENDSTOP_ABORT, &stepper.abort_on_endstop_hit);
3857
+      MENU_ITEM_EDIT(bool, MSG_ENDSTOP_ABORT, &planner.abort_on_endstop_hit);
3860 3858
     #endif
3861 3859
 
3862 3860
     END_MENU();

+ 210
- 120
Marlin/src/module/endstops.cpp 查看文件

@@ -32,18 +32,27 @@
32 32
 #include "../module/temperature.h"
33 33
 #include "../lcd/ultralcd.h"
34 34
 
35
-// TEST_ENDSTOP: test the old and the current status of an endstop
36
-#define TEST_ENDSTOP(ENDSTOP) (TEST(current_endstop_bits & old_endstop_bits, ENDSTOP))
35
+#if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
36
+  #include HAL_PATH(../HAL, endstop_interrupts.h)
37
+#endif
38
+
39
+// TEST_ENDSTOP: test the current status of an endstop
40
+#define TEST_ENDSTOP(ENDSTOP) (TEST(current_endstop_bits, ENDSTOP))
41
+
42
+#if HAS_BED_PROBE
43
+  #define ENDSTOPS_ENABLED  (endstops.enabled || endstops.z_probe_enabled)
44
+#else
45
+  #define ENDSTOPS_ENABLED  endstops.enabled
46
+#endif
37 47
 
38 48
 Endstops endstops;
39 49
 
40 50
 // public:
41 51
 
42 52
 bool Endstops::enabled, Endstops::enabled_globally; // Initialized by settings.load()
43
-volatile char Endstops::endstop_hit_bits; // use X_MIN, Y_MIN, Z_MIN and Z_MIN_PROBE as BIT value
53
+volatile uint8_t Endstops::endstop_hit_bits; // use X_MIN, Y_MIN, Z_MIN and Z_MIN_PROBE as BIT value
44 54
 
45
-Endstops::esbits_t Endstops::current_endstop_bits = 0,
46
-                   Endstops::old_endstop_bits = 0;
55
+Endstops::esbits_t Endstops::current_endstop_bits = 0;
47 56
 
48 57
 #if HAS_BED_PROBE
49 58
   volatile bool Endstops::z_probe_enabled = false;
@@ -196,8 +205,93 @@ void Endstops::init() {
196 205
     #endif
197 206
   #endif
198 207
 
208
+  #if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
209
+    setup_endstop_interrupts();
210
+  #endif
211
+
212
+  // Enable endstops
213
+  enable_globally(
214
+    #if ENABLED(ENDSTOPS_ALWAYS_ON_DEFAULT)
215
+      true
216
+    #else
217
+      false
218
+    #endif
219
+  );
220
+
199 221
 } // Endstops::init
200 222
 
223
+// Called from ISR. A change was detected. Find out what happened!
224
+void Endstops::check_possible_change() { if (ENDSTOPS_ENABLED) endstops.update(); }
225
+
226
+// Called from ISR: Poll endstop state if required
227
+void Endstops::poll() {
228
+
229
+  #if ENABLED(PINS_DEBUGGING)
230
+    endstops.run_monitor();  // report changes in endstop status
231
+  #endif
232
+
233
+  #if DISABLED(ENDSTOP_INTERRUPTS_FEATURE)
234
+    if (ENDSTOPS_ENABLED) endstops.update();
235
+  #endif
236
+}
237
+
238
+void Endstops::enable_globally(const bool onoff) {
239
+  enabled_globally = enabled = onoff;
240
+
241
+  #if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
242
+    if (onoff) endstops.update(); // If enabling, update state now
243
+  #endif
244
+}
245
+
246
+// Enable / disable endstop checking
247
+void Endstops::enable(const bool onoff) {
248
+  enabled = onoff;
249
+
250
+  #if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
251
+    if (onoff) endstops.update(); // If enabling, update state now
252
+  #endif
253
+}
254
+
255
+
256
+// Disable / Enable endstops based on ENSTOPS_ONLY_FOR_HOMING and global enable
257
+void Endstops::not_homing() {
258
+  enabled = enabled_globally;
259
+
260
+  #if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
261
+    if (enabled) endstops.update(); // If enabling, update state now
262
+  #endif
263
+}
264
+
265
+// Clear endstops (i.e., they were hit intentionally) to suppress the report
266
+void Endstops::hit_on_purpose() {
267
+  endstop_hit_bits = 0;
268
+
269
+  #if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
270
+    if (enabled) endstops.update(); // If enabling, update state now
271
+  #endif
272
+}
273
+
274
+// Enable / disable endstop z-probe checking
275
+#if HAS_BED_PROBE
276
+  void Endstops::enable_z_probe(bool onoff) {
277
+    z_probe_enabled = onoff;
278
+
279
+    #if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
280
+      if (enabled) endstops.update(); // If enabling, update state now
281
+    #endif
282
+  }
283
+#endif
284
+
285
+#if ENABLED(PINS_DEBUGGING)
286
+  void Endstops::run_monitor() {
287
+    if (!monitor_flag) return;
288
+    static uint8_t monitor_count = 16;  // offset this check from the others
289
+    monitor_count += _BV(1);            //  15 Hz
290
+    monitor_count &= 0x7F;
291
+    if (!monitor_count) monitor();      // report changes in endstop status
292
+  }
293
+#endif
294
+
201 295
 void Endstops::report_state() {
202 296
   if (endstop_hit_bits) {
203 297
     #if ENABLED(ULTRA_LCD)
@@ -208,7 +302,7 @@ void Endstops::report_state() {
208 302
     #endif
209 303
 
210 304
     #define _ENDSTOP_HIT_ECHO(A,C) do{ \
211
-      SERIAL_ECHOPAIR(" " STRINGIFY(A) ":", stepper.triggered_position_mm(_AXIS(A))); \
305
+      SERIAL_ECHOPAIR(" " STRINGIFY(A) ":", planner.triggered_position_mm(_AXIS(A))); \
212 306
       _SET_STOP_CHAR(A,C); }while(0)
213 307
 
214 308
     #define _ENDSTOP_HIT_TEST(A,C) \
@@ -238,7 +332,7 @@ void Endstops::report_state() {
238 332
     hit_on_purpose();
239 333
 
240 334
     #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) && ENABLED(SDSUPPORT)
241
-      if (stepper.abort_on_endstop_hit) {
335
+      if (planner.abort_on_endstop_hit) {
242 336
         card.sdprinting = false;
243 337
         card.closefile();
244 338
         quickstop_stepper();
@@ -300,38 +394,41 @@ void Endstops::M119() {
300 394
   #endif
301 395
 } // Endstops::M119
302 396
 
397
+// The following routines are called from an ISR context. It could be the temperature ISR, the
398
+// endstop ISR or the Stepper ISR.
399
+
303 400
 #if ENABLED(X_DUAL_ENDSTOPS)
304 401
   void Endstops::test_dual_x_endstops(const EndstopEnum es1, const EndstopEnum es2) {
305 402
     const byte x_test = TEST_ENDSTOP(es1) | (TEST_ENDSTOP(es2) << 1); // bit 0 for X, bit 1 for X2
306
-    if (x_test && stepper.current_block->steps[X_AXIS] > 0) {
403
+    if (x_test && stepper.movement_non_null(X_AXIS)) {
307 404
       SBI(endstop_hit_bits, X_MIN);
308 405
       if (!stepper.performing_homing || (x_test == 0x3))  //if not performing home or if both endstops were trigged during homing...
309
-        stepper.kill_current_block();
406
+        stepper.quick_stop();
310 407
     }
311 408
   }
312 409
 #endif
313 410
 #if ENABLED(Y_DUAL_ENDSTOPS)
314 411
   void Endstops::test_dual_y_endstops(const EndstopEnum es1, const EndstopEnum es2) {
315 412
     const byte y_test = TEST_ENDSTOP(es1) | (TEST_ENDSTOP(es2) << 1); // bit 0 for Y, bit 1 for Y2
316
-    if (y_test && stepper.current_block->steps[Y_AXIS] > 0) {
413
+    if (y_test && stepper.movement_non_null(Y_AXIS)) {
317 414
       SBI(endstop_hit_bits, Y_MIN);
318 415
       if (!stepper.performing_homing || (y_test == 0x3))  //if not performing home or if both endstops were trigged during homing...
319
-        stepper.kill_current_block();
416
+        stepper.quick_stop();
320 417
     }
321 418
   }
322 419
 #endif
323 420
 #if ENABLED(Z_DUAL_ENDSTOPS)
324 421
   void Endstops::test_dual_z_endstops(const EndstopEnum es1, const EndstopEnum es2) {
325 422
     const byte z_test = TEST_ENDSTOP(es1) | (TEST_ENDSTOP(es2) << 1); // bit 0 for Z, bit 1 for Z2
326
-    if (z_test && stepper.current_block->steps[Z_AXIS] > 0) {
423
+    if (z_test && stepper.movement_non_null(Z_AXIS)) {
327 424
       SBI(endstop_hit_bits, Z_MIN);
328 425
       if (!stepper.performing_homing || (z_test == 0x3))  //if not performing home or if both endstops were trigged during homing...
329
-        stepper.kill_current_block();
426
+        stepper.quick_stop();
330 427
     }
331 428
   }
332 429
 #endif
333 430
 
334
-// Check endstops - Called from ISR!
431
+// Check endstops - Could be called from ISR!
335 432
 void Endstops::update() {
336 433
 
337 434
   #define _ENDSTOP(AXIS, MINMAX) AXIS ##_## MINMAX
@@ -349,7 +446,7 @@ void Endstops::update() {
349 446
       UPDATE_ENDSTOP_BIT(AXIS, MINMAX); \
350 447
       if (TEST_ENDSTOP(_ENDSTOP(AXIS, MINMAX))) { \
351 448
         _ENDSTOP_HIT(AXIS, MINMAX); \
352
-        stepper.endstop_triggered(_AXIS(AXIS)); \
449
+        planner.endstop_triggered(_AXIS(AXIS)); \
353 450
       } \
354 451
     }while(0)
355 452
 
@@ -358,9 +455,9 @@ void Endstops::update() {
358 455
     if (G38_move) {
359 456
       UPDATE_ENDSTOP_BIT(Z, MIN_PROBE);
360 457
       if (TEST_ENDSTOP(_ENDSTOP(Z, MIN_PROBE))) {
361
-        if      (stepper.current_block->steps[_AXIS(X)] > 0) { _ENDSTOP_HIT(X, MIN); stepper.endstop_triggered(_AXIS(X)); }
362
-        else if (stepper.current_block->steps[_AXIS(Y)] > 0) { _ENDSTOP_HIT(Y, MIN); stepper.endstop_triggered(_AXIS(Y)); }
363
-        else if (stepper.current_block->steps[_AXIS(Z)] > 0) { _ENDSTOP_HIT(Z, MIN); stepper.endstop_triggered(_AXIS(Z)); }
458
+        if      (stepper.movement_non_null(_AXIS(X))) { _ENDSTOP_HIT(X, MIN); planner.endstop_triggered(_AXIS(X)); }
459
+        else if (stepper.movement_non_null(_AXIS(Y))) { _ENDSTOP_HIT(Y, MIN); planner.endstop_triggered(_AXIS(Y)); }
460
+        else if (stepper.movement_non_null(_AXIS(Z))) { _ENDSTOP_HIT(Z, MIN); planner.endstop_triggered(_AXIS(Z)); }
364 461
         G38_endstop_hit = true;
365 462
       }
366 463
     }
@@ -371,7 +468,7 @@ void Endstops::update() {
371 468
    */
372 469
 
373 470
   #if IS_CORE
374
-    #define S_(N) stepper.current_block->steps[CORE_AXIS_##N]
471
+    #define S_(N) stepper.movement_non_null(CORE_AXIS_##N)
375 472
     #define D_(N) stepper.motor_direction(CORE_AXIS_##N)
376 473
   #endif
377 474
 
@@ -391,7 +488,7 @@ void Endstops::update() {
391 488
     #define X_MOVE_TEST ( S_(1) != S_(2) || (S_(1) > 0 && D_(1) X_CMP D_(2)) )
392 489
     #define X_AXIS_HEAD X_HEAD
393 490
   #else
394
-    #define X_MOVE_TEST stepper.current_block->steps[X_AXIS] > 0
491
+    #define X_MOVE_TEST stepper.movement_non_null(X_AXIS)
395 492
     #define X_AXIS_HEAD X_AXIS
396 493
   #endif
397 494
 
@@ -411,7 +508,7 @@ void Endstops::update() {
411 508
     #define Y_MOVE_TEST ( S_(1) != S_(2) || (S_(1) > 0 && D_(1) Y_CMP D_(2)) )
412 509
     #define Y_AXIS_HEAD Y_HEAD
413 510
   #else
414
-    #define Y_MOVE_TEST stepper.current_block->steps[Y_AXIS] > 0
511
+    #define Y_MOVE_TEST stepper.movement_non_null(Y_AXIS)
415 512
     #define Y_AXIS_HEAD Y_AXIS
416 513
   #endif
417 514
 
@@ -431,13 +528,13 @@ void Endstops::update() {
431 528
     #define Z_MOVE_TEST ( S_(1) != S_(2) || (S_(1) > 0 && D_(1) Z_CMP D_(2)) )
432 529
     #define Z_AXIS_HEAD Z_HEAD
433 530
   #else
434
-    #define Z_MOVE_TEST stepper.current_block->steps[Z_AXIS] > 0
531
+    #define Z_MOVE_TEST stepper.movement_non_null(Z_AXIS)
435 532
     #define Z_AXIS_HEAD Z_AXIS
436 533
   #endif
437 534
 
438 535
   // With Dual X, endstops are only checked in the homing direction for the active extruder
439 536
   #if ENABLED(DUAL_X_CARRIAGE)
440
-    #define E0_ACTIVE stepper.current_block->active_extruder == 0
537
+    #define E0_ACTIVE stepper.movement_extruder() == 0
441 538
     #define X_MIN_TEST ((X_HOME_DIR < 0 && E0_ACTIVE) || (X2_HOME_DIR < 0 && !E0_ACTIVE))
442 539
     #define X_MAX_TEST ((X_HOME_DIR > 0 && E0_ACTIVE) || (X2_HOME_DIR > 0 && !E0_ACTIVE))
443 540
   #else
@@ -448,126 +545,119 @@ void Endstops::update() {
448 545
   /**
449 546
    * Check and update endstops according to conditions
450 547
    */
451
-  if (stepper.current_block) {
452
-
453
-    if (X_MOVE_TEST) {
454
-      if (stepper.motor_direction(X_AXIS_HEAD)) { // -direction
455
-        #if HAS_X_MIN
456
-          #if ENABLED(X_DUAL_ENDSTOPS)
457
-            UPDATE_ENDSTOP_BIT(X, MIN);
458
-            #if HAS_X2_MIN
459
-              UPDATE_ENDSTOP_BIT(X2, MIN);
460
-            #else
461
-              COPY_BIT(current_endstop_bits, X_MIN, X2_MIN);
462
-            #endif
463
-            test_dual_x_endstops(X_MIN, X2_MIN);
548
+  if (X_MOVE_TEST) {
549
+    if (stepper.motor_direction(X_AXIS_HEAD)) { // -direction
550
+      #if HAS_X_MIN
551
+        #if ENABLED(X_DUAL_ENDSTOPS)
552
+          UPDATE_ENDSTOP_BIT(X, MIN);
553
+          #if HAS_X2_MIN
554
+            UPDATE_ENDSTOP_BIT(X2, MIN);
464 555
           #else
465
-            if (X_MIN_TEST) UPDATE_ENDSTOP(X, MIN);
556
+            COPY_BIT(current_endstop_bits, X_MIN, X2_MIN);
466 557
           #endif
558
+          test_dual_x_endstops(X_MIN, X2_MIN);
559
+        #else
560
+          if (X_MIN_TEST) UPDATE_ENDSTOP(X, MIN);
467 561
         #endif
468
-      }
469
-      else { // +direction
470
-        #if HAS_X_MAX
471
-          #if ENABLED(X_DUAL_ENDSTOPS)
472
-            UPDATE_ENDSTOP_BIT(X, MAX);
473
-            #if HAS_X2_MAX
474
-              UPDATE_ENDSTOP_BIT(X2, MAX);
475
-            #else
476
-              COPY_BIT(current_endstop_bits, X_MAX, X2_MAX);
477
-            #endif
478
-            test_dual_x_endstops(X_MAX, X2_MAX);
562
+      #endif
563
+    }
564
+    else { // +direction
565
+      #if HAS_X_MAX
566
+        #if ENABLED(X_DUAL_ENDSTOPS)
567
+          UPDATE_ENDSTOP_BIT(X, MAX);
568
+          #if HAS_X2_MAX
569
+            UPDATE_ENDSTOP_BIT(X2, MAX);
479 570
           #else
480
-            if (X_MAX_TEST) UPDATE_ENDSTOP(X, MAX);
571
+            COPY_BIT(current_endstop_bits, X_MAX, X2_MAX);
481 572
           #endif
573
+          test_dual_x_endstops(X_MAX, X2_MAX);
574
+        #else
575
+          if (X_MAX_TEST) UPDATE_ENDSTOP(X, MAX);
482 576
         #endif
483
-      }
577
+      #endif
484 578
     }
579
+  }
485 580
 
486
-    if (Y_MOVE_TEST) {
487
-      if (stepper.motor_direction(Y_AXIS_HEAD)) { // -direction
488
-        #if HAS_Y_MIN
489
-          #if ENABLED(Y_DUAL_ENDSTOPS)
490
-            UPDATE_ENDSTOP_BIT(Y, MIN);
491
-            #if HAS_Y2_MIN
492
-              UPDATE_ENDSTOP_BIT(Y2, MIN);
493
-            #else
494
-              COPY_BIT(current_endstop_bits, Y_MIN, Y2_MIN);
495
-            #endif
496
-            test_dual_y_endstops(Y_MIN, Y2_MIN);
581
+  if (Y_MOVE_TEST) {
582
+    if (stepper.motor_direction(Y_AXIS_HEAD)) { // -direction
583
+      #if HAS_Y_MIN
584
+        #if ENABLED(Y_DUAL_ENDSTOPS)
585
+          UPDATE_ENDSTOP_BIT(Y, MIN);
586
+          #if HAS_Y2_MIN
587
+            UPDATE_ENDSTOP_BIT(Y2, MIN);
497 588
           #else
498
-            UPDATE_ENDSTOP(Y, MIN);
589
+            COPY_BIT(current_endstop_bits, Y_MIN, Y2_MIN);
499 590
           #endif
591
+          test_dual_y_endstops(Y_MIN, Y2_MIN);
592
+        #else
593
+          UPDATE_ENDSTOP(Y, MIN);
500 594
         #endif
501
-      }
502
-      else { // +direction
503
-        #if HAS_Y_MAX
504
-          #if ENABLED(Y_DUAL_ENDSTOPS)
505
-            UPDATE_ENDSTOP_BIT(Y, MAX);
506
-            #if HAS_Y2_MAX
507
-              UPDATE_ENDSTOP_BIT(Y2, MAX);
508
-            #else
509
-              COPY_BIT(current_endstop_bits, Y_MAX, Y2_MAX);
510
-            #endif
511
-            test_dual_y_endstops(Y_MAX, Y2_MAX);
595
+      #endif
596
+    }
597
+    else { // +direction
598
+      #if HAS_Y_MAX
599
+        #if ENABLED(Y_DUAL_ENDSTOPS)
600
+          UPDATE_ENDSTOP_BIT(Y, MAX);
601
+          #if HAS_Y2_MAX
602
+            UPDATE_ENDSTOP_BIT(Y2, MAX);
512 603
           #else
513
-            UPDATE_ENDSTOP(Y, MAX);
604
+            COPY_BIT(current_endstop_bits, Y_MAX, Y2_MAX);
514 605
           #endif
606
+          test_dual_y_endstops(Y_MAX, Y2_MAX);
607
+        #else
608
+          UPDATE_ENDSTOP(Y, MAX);
515 609
         #endif
516
-      }
610
+      #endif
517 611
     }
612
+  }
518 613
 
519
-    if (Z_MOVE_TEST) {
520
-      if (stepper.motor_direction(Z_AXIS_HEAD)) { // Z -direction. Gantry down, bed up.
521
-        #if HAS_Z_MIN
522
-          #if ENABLED(Z_DUAL_ENDSTOPS)
523
-            UPDATE_ENDSTOP_BIT(Z, MIN);
524
-            #if HAS_Z2_MIN
525
-              UPDATE_ENDSTOP_BIT(Z2, MIN);
526
-            #else
527
-              COPY_BIT(current_endstop_bits, Z_MIN, Z2_MIN);
528
-            #endif
529
-            test_dual_z_endstops(Z_MIN, Z2_MIN);
614
+  if (Z_MOVE_TEST) {
615
+    if (stepper.motor_direction(Z_AXIS_HEAD)) { // Z -direction. Gantry down, bed up.
616
+      #if HAS_Z_MIN
617
+        #if ENABLED(Z_DUAL_ENDSTOPS)
618
+          UPDATE_ENDSTOP_BIT(Z, MIN);
619
+          #if HAS_Z2_MIN
620
+            UPDATE_ENDSTOP_BIT(Z2, MIN);
621
+          #else
622
+            COPY_BIT(current_endstop_bits, Z_MIN, Z2_MIN);
623
+          #endif
624
+          test_dual_z_endstops(Z_MIN, Z2_MIN);
625
+        #else
626
+          #if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
627
+            if (z_probe_enabled) UPDATE_ENDSTOP(Z, MIN);
530 628
           #else
531
-            #if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
532
-              if (z_probe_enabled) UPDATE_ENDSTOP(Z, MIN);
533
-            #else
534
-              UPDATE_ENDSTOP(Z, MIN);
535
-            #endif
629
+            UPDATE_ENDSTOP(Z, MIN);
536 630
           #endif
537 631
         #endif
632
+      #endif
538 633
 
539
-        // When closing the gap check the enabled probe
540
-        #if ENABLED(Z_MIN_PROBE_ENDSTOP)
541
-          if (z_probe_enabled) {
542
-            UPDATE_ENDSTOP(Z, MIN_PROBE);
543
-            if (TEST_ENDSTOP(Z_MIN_PROBE)) SBI(endstop_hit_bits, Z_MIN_PROBE);
544
-          }
545
-        #endif
546
-      }
547
-      else { // Z +direction. Gantry up, bed down.
548
-        #if HAS_Z_MAX
549
-          // Check both Z dual endstops
550
-          #if ENABLED(Z_DUAL_ENDSTOPS)
551
-            UPDATE_ENDSTOP_BIT(Z, MAX);
552
-            #if HAS_Z2_MAX
553
-              UPDATE_ENDSTOP_BIT(Z2, MAX);
554
-            #else
555
-              COPY_BIT(current_endstop_bits, Z_MAX, Z2_MAX);
556
-            #endif
557
-            test_dual_z_endstops(Z_MAX, Z2_MAX);
558
-          // If this pin is not hijacked for the bed probe
559
-          // then it belongs to the Z endstop
560
-          #elif DISABLED(Z_MIN_PROBE_ENDSTOP) || Z_MAX_PIN != Z_MIN_PROBE_PIN
561
-            UPDATE_ENDSTOP(Z, MAX);
634
+      // When closing the gap check the enabled probe
635
+      #if ENABLED(Z_MIN_PROBE_ENDSTOP)
636
+        if (z_probe_enabled) {
637
+          UPDATE_ENDSTOP(Z, MIN_PROBE);
638
+          if (TEST_ENDSTOP(Z_MIN_PROBE)) SBI(endstop_hit_bits, Z_MIN_PROBE);
639
+        }
640
+      #endif
641
+    }
642
+    else { // Z +direction. Gantry up, bed down.
643
+      #if HAS_Z_MAX
644
+        // Check both Z dual endstops
645
+        #if ENABLED(Z_DUAL_ENDSTOPS)
646
+          UPDATE_ENDSTOP_BIT(Z, MAX);
647
+          #if HAS_Z2_MAX
648
+            UPDATE_ENDSTOP_BIT(Z2, MAX);
649
+          #else
650
+            COPY_BIT(current_endstop_bits, Z_MAX, Z2_MAX);
562 651
           #endif
652
+          test_dual_z_endstops(Z_MAX, Z2_MAX);
653
+        // If this pin is not hijacked for the bed probe
654
+        // then it belongs to the Z endstop
655
+        #elif DISABLED(Z_MIN_PROBE_ENDSTOP) || Z_MAX_PIN != Z_MIN_PROBE_PIN
656
+          UPDATE_ENDSTOP(Z, MAX);
563 657
         #endif
564
-      }
658
+      #endif
565 659
     }
566
-
567
-  } // stepper.current_block
568
-
569
-  old_endstop_bits = current_endstop_bits;
570
-
660
+  }
571 661
 } // Endstops::update()
572 662
 
573 663
 #if ENABLED(PINS_DEBUGGING)

+ 20
- 29
Marlin/src/module/endstops.h 查看文件

@@ -51,7 +51,7 @@ class Endstops {
51 51
   public:
52 52
 
53 53
     static bool enabled, enabled_globally;
54
-    static volatile char endstop_hit_bits; // use X_MIN, Y_MIN, Z_MIN and Z_MIN_PROBE as BIT value
54
+    static volatile uint8_t endstop_hit_bits; // use X_MIN, Y_MIN, Z_MIN and Z_MIN_PROBE as BIT value
55 55
 
56 56
     #if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
57 57
       typedef uint16_t esbits_t;
@@ -68,17 +68,9 @@ class Endstops {
68 68
       typedef byte esbits_t;
69 69
     #endif
70 70
 
71
-    static esbits_t current_endstop_bits, old_endstop_bits;
71
+    static esbits_t current_endstop_bits;
72 72
 
73
-    Endstops() {
74
-      enable_globally(
75
-        #if ENABLED(ENDSTOPS_ALWAYS_ON_DEFAULT)
76
-          true
77
-        #else
78
-          false
79
-        #endif
80
-      );
81
-    };
73
+    Endstops() {};
82 74
 
83 75
     /**
84 76
      * Initialize the endstop pins
@@ -86,6 +78,17 @@ class Endstops {
86 78
     static void init();
87 79
 
88 80
     /**
81
+     * A change was detected or presumed to be in endstops pins. Find out what
82
+     * changed, if anything. Called from ISR contexts
83
+     */
84
+    static void check_possible_change();
85
+
86
+    /**
87
+     * Periodic call to poll endstops if required. Called from temperature ISR
88
+     */
89
+    static void poll();
90
+
91
+    /**
89 92
      * Update the endstops bits from the pins
90 93
      */
91 94
     static void update();
@@ -101,34 +104,28 @@ class Endstops {
101 104
     static void M119();
102 105
 
103 106
     // Enable / disable endstop checking globally
104
-    static void enable_globally(bool onoff=true) { enabled_globally = enabled = onoff; }
107
+    static void enable_globally(const bool onoff=true);
105 108
 
106 109
     // Enable / disable endstop checking
107
-    static void enable(bool onoff=true) { enabled = onoff; }
110
+    static void enable(const bool onoff=true);
108 111
 
109 112
     // Disable / Enable endstops based on ENSTOPS_ONLY_FOR_HOMING and global enable
110
-    static void not_homing() { enabled = enabled_globally; }
113
+    static void not_homing();
111 114
 
112 115
     // Clear endstops (i.e., they were hit intentionally) to suppress the report
113
-    static void hit_on_purpose() { endstop_hit_bits = 0; }
116
+    static void hit_on_purpose();
114 117
 
115 118
     // Enable / disable endstop z-probe checking
116 119
     #if HAS_BED_PROBE
117 120
       static volatile bool z_probe_enabled;
118
-      static void enable_z_probe(bool onoff=true) { z_probe_enabled = onoff; }
121
+      static void enable_z_probe(bool onoff=true);
119 122
     #endif
120 123
 
121 124
     // Debugging of endstops
122 125
     #if ENABLED(PINS_DEBUGGING)
123 126
       static bool monitor_flag;
124 127
       static void monitor();
125
-      FORCE_INLINE static void run_monitor() {
126
-        if (!monitor_flag) return;
127
-        static uint8_t monitor_count = 16;  // offset this check from the others
128
-        monitor_count += _BV(1);            //  15 Hz
129
-        monitor_count &= 0x7F;
130
-        if (!monitor_count) monitor();      // report changes in endstop status
131
-      }
128
+      static void run_monitor();
132 129
     #endif
133 130
 
134 131
   private:
@@ -146,10 +143,4 @@ class Endstops {
146 143
 
147 144
 extern Endstops endstops;
148 145
 
149
-#if HAS_BED_PROBE
150
-  #define ENDSTOPS_ENABLED  (endstops.enabled || endstops.z_probe_enabled)
151
-#else
152
-  #define ENDSTOPS_ENABLED  endstops.enabled
153
-#endif
154
-
155 146
 #endif // __ENDSTOPS_H__

+ 12
- 9
Marlin/src/module/motion.cpp 查看文件

@@ -644,7 +644,8 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
644 644
       #if ENABLED(SCARA_FEEDRATE_SCALING)
645 645
         // For SCARA scale the feed rate from mm/s to degrees/s
646 646
         // i.e., Complete the angular vector in the given time.
647
-        planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], raw[Z_AXIS], raw[E_AXIS], HYPOT(delta[A_AXIS] - oldA, delta[B_AXIS] - oldB) * inverse_secs, active_extruder);
647
+        if (!planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], raw[Z_AXIS], raw[E_AXIS], HYPOT(delta[A_AXIS] - oldA, delta[B_AXIS] - oldB) * inverse_secs, active_extruder))
648
+          break;
648 649
         /*
649 650
         SERIAL_ECHO(segments);
650 651
         SERIAL_ECHOPAIR(": X=", raw[X_AXIS]); SERIAL_ECHOPAIR(" Y=", raw[Y_AXIS]);
@@ -654,7 +655,8 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
654 655
         //*/
655 656
         oldA = delta[A_AXIS]; oldB = delta[B_AXIS];
656 657
       #else
657
-        planner.buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], raw[E_AXIS], _feedrate_mm_s, active_extruder, cartesian_segment_mm);
658
+        if (!planner.buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], raw[E_AXIS], _feedrate_mm_s, active_extruder, cartesian_segment_mm))
659
+          break;
658 660
       #endif
659 661
     }
660 662
 
@@ -746,7 +748,8 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
746 748
           idle();
747 749
         }
748 750
         LOOP_XYZE(i) raw[i] += segment_distance[i];
749
-        planner.buffer_line_kinematic(raw, fr_mm_s, active_extruder, cartesian_segment_mm);
751
+        if (!planner.buffer_line_kinematic(raw, fr_mm_s, active_extruder, cartesian_segment_mm))
752
+          break;
750 753
       }
751 754
 
752 755
       // Since segment_distance is only approximate,
@@ -848,14 +851,14 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
848 851
           }
849 852
           // unpark extruder: 1) raise, 2) move into starting XY position, 3) lower
850 853
           for (uint8_t i = 0; i < 3; i++)
851
-            planner.buffer_line(
854
+            if (!planner.buffer_line(
852 855
               i == 0 ? raised_parked_position[X_AXIS] : current_position[X_AXIS],
853 856
               i == 0 ? raised_parked_position[Y_AXIS] : current_position[Y_AXIS],
854 857
               i == 2 ? current_position[Z_AXIS] : raised_parked_position[Z_AXIS],
855 858
               current_position[E_AXIS],
856 859
               i == 1 ? PLANNER_XY_FEEDRATE() : planner.max_feedrate_mm_s[Z_AXIS],
857
-              active_extruder
858
-            );
860
+              active_extruder)
861
+            ) break;
859 862
           delayed_move_time = 0;
860 863
           active_extruder_parked = false;
861 864
           #if ENABLED(DEBUG_LEVELING_FEATURE)
@@ -872,11 +875,11 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
872 875
             #endif
873 876
             // move duplicate extruder into correct duplication position.
874 877
             planner.set_position_mm(inactive_extruder_x_pos, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
875
-            planner.buffer_line(
878
+            if (!planner.buffer_line(
876 879
               current_position[X_AXIS] + duplicate_extruder_x_offset,
877 880
               current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS],
878
-              planner.max_feedrate_mm_s[X_AXIS], 1
879
-            );
881
+              planner.max_feedrate_mm_s[X_AXIS], 1)
882
+            ) break;
880 883
             planner.synchronize();
881 884
             SYNC_PLAN_POSITION_KINEMATIC();
882 885
             extruder_duplication_enabled = true;

+ 475
- 252
Marlin/src/module/planner.cpp
文件差异内容过多而无法显示
查看文件


+ 185
- 90
Marlin/src/module/planner.h 查看文件

@@ -35,6 +35,7 @@
35 35
 #include "../Marlin.h"
36 36
 
37 37
 #include "motion.h"
38
+#include "../gcode/queue.h"
38 39
 
39 40
 #if ENABLED(DELTA)
40 41
   #include "delta.h"
@@ -53,7 +54,7 @@ enum BlockFlagBit : char {
53 54
   // from a safe speed (in consideration of jerking from zero speed).
54 55
   BLOCK_BIT_NOMINAL_LENGTH,
55 56
 
56
-  // The block is busy
57
+  // The block is busy, being interpreted by the stepper ISR
57 58
   BLOCK_BIT_BUSY,
58 59
 
59 60
   // The block is segment 2+ of a longer move
@@ -84,19 +85,35 @@ typedef struct {
84 85
 
85 86
   uint8_t flag;                             // Block flags (See BlockFlag enum above)
86 87
 
87
-  unsigned char active_extruder;            // The extruder to move (if E move)
88
+  // Fields used by the motion planner to manage acceleration
89
+  float nominal_speed_sqr,                  // The nominal speed for this block in (mm/sec)^2
90
+        entry_speed_sqr,                    // Entry speed at previous-current junction in (mm/sec)^2
91
+        max_entry_speed_sqr,                // Maximum allowable junction entry speed in (mm/sec)^2
92
+        millimeters,                        // The total travel of this block in mm
93
+        acceleration;                       // acceleration mm/sec^2
88 94
 
89
-  // Fields used by the Bresenham algorithm for tracing the line
90
-  int32_t steps[NUM_AXIS];                  // Step count along each axis
95
+  union {
96
+    // Data used by all move blocks
97
+    struct {
98
+      // Fields used by the Bresenham algorithm for tracing the line
99
+      uint32_t steps[NUM_AXIS];             // Step count along each axis
100
+    };
101
+    // Data used by all sync blocks
102
+    struct {
103
+      int32_t position[NUM_AXIS];           // New position to force when this sync block is executed
104
+    };
105
+  };
91 106
   uint32_t step_event_count;                // The number of step events required to complete this block
92 107
 
108
+  uint8_t active_extruder;                  // The extruder to move (if E move)
109
+
93 110
   #if ENABLED(MIXING_EXTRUDER)
94 111
     uint32_t mix_event_count[MIXING_STEPPERS]; // Scaled step_event_count for the mixing steppers
95 112
   #endif
96 113
 
97 114
   // Settings for the trapezoid generator
98
-  int32_t accelerate_until,                 // The index of the step event on which to stop acceleration
99
-          decelerate_after;                 // The index of the step event on which to start decelerating
115
+  uint32_t accelerate_until,                // The index of the step event on which to stop acceleration
116
+           decelerate_after;                // The index of the step event on which to start decelerating
100 117
 
101 118
   #if ENABLED(BEZIER_JERK_CONTROL)
102 119
     uint32_t cruise_rate;                   // The actual cruise rate to use, between end of the acceleration phase and start of deceleration phase
@@ -105,7 +122,7 @@ typedef struct {
105 122
     uint32_t acceleration_time_inverse,     // Inverse of acceleration and deceleration periods, expressed as integer. Scale depends on CPU being used
106 123
              deceleration_time_inverse;
107 124
   #else
108
-    int32_t acceleration_rate;              // The acceleration rate used for acceleration calculation
125
+    uint32_t acceleration_rate;             // The acceleration rate used for acceleration calculation
109 126
   #endif
110 127
 
111 128
   uint8_t direction_bits;                   // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
@@ -119,13 +136,6 @@ typedef struct {
119 136
     float e_D_ratio;
120 137
   #endif
121 138
 
122
-  // Fields used by the motion planner to manage acceleration
123
-  float nominal_speed,                      // The nominal speed for this block in mm/sec
124
-        entry_speed,                        // Entry speed at previous-current junction in mm/sec
125
-        max_entry_speed,                    // Maximum allowable junction entry speed in mm/sec
126
-        millimeters,                        // The total travel of this block in mm
127
-        acceleration;                       // acceleration mm/sec^2
128
-
129 139
   uint32_t nominal_rate,                    // The nominal step rate for this block in step_events/sec
130 140
            initial_rate,                    // The jerk-adjusted step rate at start of block
131 141
            final_rate,                      // The minimal rate at exit
@@ -166,6 +176,10 @@ class Planner {
166 176
     static block_t block_buffer[BLOCK_BUFFER_SIZE];
167 177
     static volatile uint8_t block_buffer_head,      // Index of the next block to be pushed
168 178
                             block_buffer_tail;      // Index of the busy block, if any
179
+    static uint16_t cleaning_buffer_counter;        // A counter to disable queuing of blocks
180
+    static uint8_t delay_before_delivering,         // This counter delays delivery of blocks when queue becomes empty to allow the opportunity of merging blocks
181
+                   block_buffer_planned;            // Index of the optimally planned block
182
+                   
169 183
 
170 184
     #if ENABLED(DISTINCT_E_FACTORS)
171 185
       static uint8_t last_extruder;                 // Respond to extruder change
@@ -233,6 +247,10 @@ class Planner {
233 247
       #endif
234 248
     #endif
235 249
 
250
+    #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
251
+      static bool abort_on_endstop_hit;
252
+    #endif
253
+
236 254
   private:
237 255
 
238 256
     /**
@@ -247,9 +265,9 @@ class Planner {
247 265
     static float previous_speed[NUM_AXIS];
248 266
 
249 267
     /**
250
-     * Nominal speed of previous path line segment
268
+     * Nominal speed of previous path line segment (mm/s)^2
251 269
      */
252
-    static float previous_nominal_speed;
270
+    static float previous_nominal_speed_sqr;
253 271
 
254 272
     /**
255 273
      * Limit where 64bit math is necessary for acceleration calculation
@@ -308,15 +326,6 @@ class Planner {
308 326
     // Manage fans, paste pressure, etc.
309 327
     static void check_axes_activity();
310 328
 
311
-    /**
312
-     * Number of moves currently in the planner
313
-     */
314
-    FORCE_INLINE static uint8_t movesplanned() { return BLOCK_MOD(block_buffer_head - block_buffer_tail + BLOCK_BUFFER_SIZE); }
315
-
316
-    FORCE_INLINE static void clear_block_buffer() { block_buffer_head = block_buffer_tail = 0; }
317
-
318
-    FORCE_INLINE static bool is_full() { return block_buffer_tail == next_block_index(block_buffer_head); }
319
-
320 329
     // Update multipliers based on new diameter measurements
321 330
     static void calculate_volumetric_multipliers();
322 331
 
@@ -424,16 +433,32 @@ class Planner {
424 433
       #define ARG_Z const float &rz
425 434
     #endif
426 435
 
436
+    // Number of moves currently in the planner
437
+    FORCE_INLINE static uint8_t movesplanned() { return BLOCK_MOD(block_buffer_head - block_buffer_tail); }
438
+
439
+    // Remove all blocks from the buffer
440
+    FORCE_INLINE static void clear_block_buffer() { block_buffer_head = block_buffer_tail = 0; }
441
+
442
+    // Check if movement queue is full
443
+    FORCE_INLINE static bool is_full() { return block_buffer_tail == next_block_index(block_buffer_head); }
444
+
445
+    // Get count of movement slots free
446
+    FORCE_INLINE static uint8_t moves_free() { return BLOCK_BUFFER_SIZE - 1 - movesplanned(); }
447
+
427 448
     /**
428 449
      * Planner::get_next_free_block
429 450
      *
430
-     * - Get the next head index (passed by reference)
431
-     * - Wait for a space to open up in the planner
432
-     * - Return the head block
451
+     * - Get the next head indices (passed by reference)
452
+     * - Wait for the number of spaces to open up in the planner
453
+     * - Return the first head block
433 454
      */
434
-    FORCE_INLINE static block_t* get_next_free_block(uint8_t &next_buffer_head) {
455
+    FORCE_INLINE static block_t* get_next_free_block(uint8_t &next_buffer_head, uint8_t count = 1) {
456
+
457
+      // Wait until there are enough slots free
458
+      while (moves_free() < count) { idle(); }
459
+
460
+      // Return the first available block
435 461
       next_buffer_head = next_block_index(block_buffer_head);
436
-      while (block_buffer_tail == next_buffer_head) idle(); // while (is_full)
437 462
       return &block_buffer[block_buffer_head];
438 463
     }
439 464
 
@@ -446,8 +471,30 @@ class Planner {
446 471
      *  fr_mm_s     - (target) speed of the move
447 472
      *  extruder    - target extruder
448 473
      *  millimeters - the length of the movement, if known
474
+     *
475
+     * Returns true if movement was buffered, false otherwise
449 476
      */
450
-    static void _buffer_steps(const int32_t (&target)[XYZE]
477
+    static bool _buffer_steps(const int32_t (&target)[XYZE]
478
+      #if HAS_POSITION_FLOAT
479
+        , const float (&target_float)[XYZE]
480
+      #endif
481
+      , float fr_mm_s, const uint8_t extruder, const float &millimeters=0.0
482
+    );
483
+
484
+    /**
485
+     * Planner::_populate_block
486
+     *
487
+     * Fills a new linear movement in the block (in terms of steps).
488
+     *
489
+     *  target      - target position in steps units
490
+     *  fr_mm_s     - (target) speed of the move
491
+     *  extruder    - target extruder
492
+     *  millimeters - the length of the movement, if known
493
+     *
494
+     * Returns true is movement is acceptable, false otherwise
495
+     */
496
+    static bool _populate_block(block_t * const block, bool split_move,
497
+        const int32_t (&target)[XYZE]
451 498
       #if HAS_POSITION_FLOAT
452 499
         , const float (&target_float)[XYZE]
453 500
       #endif
@@ -472,7 +519,7 @@ class Planner {
472 519
      *  extruder    - target extruder
473 520
      *  millimeters - the length of the movement, if known
474 521
      */
475
-    static void buffer_segment(const float &a, const float &b, const float &c, const float &e, const float &fr_mm_s, const uint8_t extruder, const float &millimeters=0.0);
522
+    static bool buffer_segment(const float &a, const float &b, const float &c, const float &e, const float &fr_mm_s, const uint8_t extruder, const float &millimeters=0.0);
476 523
 
477 524
     static void _set_position_mm(const float &a, const float &b, const float &c, const float &e);
478 525
 
@@ -489,11 +536,11 @@ class Planner {
489 536
      *  extruder     - target extruder
490 537
      *  millimeters  - the length of the movement, if known
491 538
      */
492
-    FORCE_INLINE static void buffer_line(ARG_X, ARG_Y, ARG_Z, const float &e, const float &fr_mm_s, const uint8_t extruder, const float millimeters = 0.0) {
539
+    FORCE_INLINE static bool buffer_line(ARG_X, ARG_Y, ARG_Z, const float &e, const float &fr_mm_s, const uint8_t extruder, const float millimeters = 0.0) {
493 540
       #if PLANNER_LEVELING && IS_CARTESIAN
494 541
         apply_leveling(rx, ry, rz);
495 542
       #endif
496
-      buffer_segment(rx, ry, rz, e, fr_mm_s, extruder, millimeters);
543
+      return buffer_segment(rx, ry, rz, e, fr_mm_s, extruder, millimeters);
497 544
     }
498 545
 
499 546
     /**
@@ -506,7 +553,7 @@ class Planner {
506 553
      *  extruder     - target extruder
507 554
      *  millimeters  - the length of the movement, if known
508 555
      */
509
-    FORCE_INLINE static void buffer_line_kinematic(const float (&cart)[XYZE], const float &fr_mm_s, const uint8_t extruder, const float millimeters = 0.0) {
556
+    FORCE_INLINE static bool buffer_line_kinematic(const float (&cart)[XYZE], const float &fr_mm_s, const uint8_t extruder, const float millimeters = 0.0) {
510 557
       #if PLANNER_LEVELING
511 558
         float raw[XYZ] = { cart[X_AXIS], cart[Y_AXIS], cart[Z_AXIS] };
512 559
         apply_leveling(raw);
@@ -515,9 +562,9 @@ class Planner {
515 562
       #endif
516 563
       #if IS_KINEMATIC
517 564
         inverse_kinematics(raw);
518
-        buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], cart[E_AXIS], fr_mm_s, extruder, millimeters);
565
+        return buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], cart[E_AXIS], fr_mm_s, extruder, millimeters);
519 566
       #else
520
-        buffer_segment(raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS], cart[E_AXIS], fr_mm_s, extruder, millimeters);
567
+        return buffer_segment(raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS], cart[E_AXIS], fr_mm_s, extruder, millimeters);
521 568
       #endif
522 569
     }
523 570
 
@@ -542,11 +589,6 @@ class Planner {
542 589
     FORCE_INLINE static void set_e_position_mm(const float &e) { set_position_mm(E_AXIS, e); }
543 590
 
544 591
     /**
545
-     * Sync from the stepper positions. (e.g., after an interrupted move)
546
-     */
547
-    static void sync_from_steppers();
548
-
549
-    /**
550 592
      * Get an axis position according to stepper position(s)
551 593
      * For CORE machines apply translation from ABC to XYZ.
552 594
      */
@@ -557,34 +599,37 @@ class Planner {
557 599
       FORCE_INLINE static float get_axis_position_degrees(const AxisEnum axis) { return get_axis_position_mm(axis); }
558 600
     #endif
559 601
 
560
-    /**
561
-     * Does the buffer have any blocks queued?
562
-     */
563
-    FORCE_INLINE static bool has_blocks_queued() { return (block_buffer_head != block_buffer_tail); }
602
+    // Called to force a quick stop of the machine (for example, when an emergency
603
+    // stop is required, or when endstops are hit)
604
+    static void quick_stop();
605
+
606
+    // Called when an endstop is triggered. Causes the machine to stop inmediately
607
+    static void endstop_triggered(const AxisEnum axis);
564 608
 
565
-    //
566
-    // Block until all buffered steps are executed
567
-    //
609
+    // Triggered position of an axis in mm (not core-savvy)
610
+    static float triggered_position_mm(const AxisEnum axis);
611
+
612
+    // Block until all buffered steps are executed / cleaned
568 613
     static void synchronize();
569 614
 
570
-    /**
571
-     * "Discard" the block and "release" the memory.
572
-     * Called when the current block is no longer needed.
573
-     */
574
-    FORCE_INLINE static void discard_current_block() {
575
-      if (has_blocks_queued())
576
-        block_buffer_tail = BLOCK_MOD(block_buffer_tail + 1);
615
+    // Wait for moves to finish and disable all steppers
616
+    static void finish_and_disable();
617
+
618
+    // Periodic tick to handle cleaning timeouts
619
+    // Called from the Temperature ISR at ~1kHz
620
+    static void tick() {
621
+      if (cleaning_buffer_counter) {
622
+        --cleaning_buffer_counter;
623
+        #if ENABLED(SD_FINISHED_STEPPERRELEASE) && defined(SD_FINISHED_RELEASECOMMAND)
624
+          if (!cleaning_buffer_counter) enqueue_and_echo_commands_P(PSTR(SD_FINISHED_RELEASECOMMAND));
625
+        #endif
626
+      }
577 627
     }
578 628
 
579 629
     /**
580
-     * "Discard" the next block if it's continued.
581
-     * Called after an interrupted move to throw away the rest of the move.
630
+     * Does the buffer have any blocks queued?
582 631
      */
583
-    FORCE_INLINE static bool discard_continued_block() {
584
-      const bool discard = has_blocks_queued() && TEST(block_buffer[block_buffer_tail].flag, BLOCK_BIT_CONTINUED);
585
-      if (discard) discard_current_block();
586
-      return discard;
587
-    }
632
+    FORCE_INLINE static bool has_blocks_queued() { return (block_buffer_head != block_buffer_tail); }
588 633
 
589 634
     /**
590 635
      * The current block. NULL if the buffer is empty.
@@ -592,38 +637,78 @@ class Planner {
592 637
      * WARNING: Called from Stepper ISR context!
593 638
      */
594 639
     static block_t* get_current_block() {
595
-      if (has_blocks_queued()) {
596
-        block_t * const block = &block_buffer[block_buffer_tail];
597 640
 
598
-        // If the block has no trapezoid calculated, it's unsafe to execute.
599
-        if (movesplanned() > 1) {
600
-          const block_t * const next = &block_buffer[next_block_index(block_buffer_tail)];
601
-          if (TEST(block->flag, BLOCK_BIT_RECALCULATE) || TEST(next->flag, BLOCK_BIT_RECALCULATE))
602
-            return NULL;
641
+      // Get the number of moves in the planner queue so far
642
+      uint8_t nr_moves = movesplanned();
643
+
644
+      // If there are any moves queued ...
645
+      if (nr_moves) {
646
+
647
+        // If there is still delay of delivery of blocks running, decrement it
648
+        if (delay_before_delivering) {
649
+          --delay_before_delivering;
650
+          // If the number of movements queued is less than 3, and there is still time
651
+          //  to wait, do not deliver anything
652
+          if (nr_moves < 3 && delay_before_delivering) return NULL;
653
+          delay_before_delivering = 0;
603 654
         }
604
-        else if (TEST(block->flag, BLOCK_BIT_RECALCULATE))
605
-          return NULL;
655
+
656
+        // If we are here, there is no excuse to deliver the block
657
+        block_t * const block = &block_buffer[block_buffer_tail];
658
+
659
+        // No trapezoid calculated? Don't execute yet.
660
+        if (TEST(block->flag, BLOCK_BIT_RECALCULATE)) return NULL;
606 661
 
607 662
         #if ENABLED(ULTRA_LCD)
608 663
           block_buffer_runtime_us -= block->segment_time_us; // We can't be sure how long an active block will take, so don't count it.
609 664
         #endif
665
+
666
+        // Mark the block as busy, so the planner does not attempt to replan it
610 667
         SBI(block->flag, BLOCK_BIT_BUSY);
611 668
         return block;
612 669
       }
613
-      else {
614
-        #if ENABLED(ULTRA_LCD)
615
-          clear_block_buffer_runtime(); // paranoia. Buffer is empty now - so reset accumulated time to zero.
616
-        #endif
617
-        return NULL;
670
+
671
+      // The queue became empty
672
+      #if ENABLED(ULTRA_LCD)
673
+        clear_block_buffer_runtime(); // paranoia. Buffer is empty now - so reset accumulated time to zero.
674
+      #endif
675
+
676
+      return NULL;
677
+    }
678
+
679
+    /**
680
+     * "Discard" the block and "release" the memory.
681
+     * Called when the current block is no longer needed.
682
+     * NB: There MUST be a current block to call this function!!
683
+     */
684
+    FORCE_INLINE static void discard_current_block() {
685
+      if (has_blocks_queued()) { // Discard non-empty buffer.
686
+        uint8_t block_index = next_block_index( block_buffer_tail );
687
+
688
+        // Push block_buffer_planned pointer, if encountered.
689
+        if (!has_blocks_queued()) block_buffer_planned = block_index;
690
+
691
+        block_buffer_tail = block_index;
618 692
       }
619 693
     }
620 694
 
621 695
     #if ENABLED(ULTRA_LCD)
622 696
 
623 697
       static uint16_t block_buffer_runtime() {
624
-        CRITICAL_SECTION_START
625
-          millis_t bbru = block_buffer_runtime_us;
626
-        CRITICAL_SECTION_END
698
+        #ifdef __AVR__
699
+          // Protect the access to the variable. Only required for AVR, as
700
+          //  any 32bit CPU offers atomic access to 32bit variables
701
+          bool was_enabled = STEPPER_ISR_ENABLED();
702
+          if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
703
+        #endif
704
+
705
+        millis_t bbru = block_buffer_runtime_us;
706
+
707
+        #ifdef __AVR__
708
+          // Reenable Stepper ISR
709
+          if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
710
+        #endif
711
+
627 712
         // To translate µs to ms a division by 1000 would be required.
628 713
         // We introduce 2.4% error here by dividing by 1024.
629 714
         // Doesn't matter because block_buffer_runtime_us is already too small an estimation.
@@ -634,9 +719,19 @@ class Planner {
634 719
       }
635 720
 
636 721
       static void clear_block_buffer_runtime() {
637
-        CRITICAL_SECTION_START
638
-          block_buffer_runtime_us = 0;
639
-        CRITICAL_SECTION_END
722
+        #ifdef __AVR__
723
+          // Protect the access to the variable. Only required for AVR, as
724
+          //  any 32bit CPU offers atomic access to 32bit variables
725
+          bool was_enabled = STEPPER_ISR_ENABLED();
726
+          if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
727
+        #endif
728
+
729
+        block_buffer_runtime_us = 0;
730
+
731
+        #ifdef __AVR__
732
+          // Reenable Stepper ISR
733
+          if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
734
+        #endif
640 735
       }
641 736
 
642 737
     #endif
@@ -653,8 +748,8 @@ class Planner {
653 748
     /**
654 749
      * Get the index of the next / previous block in the ring buffer
655 750
      */
656
-    static constexpr int8_t next_block_index(const int8_t block_index) { return BLOCK_MOD(block_index + 1); }
657
-    static constexpr int8_t prev_block_index(const int8_t block_index) { return BLOCK_MOD(block_index - 1); }
751
+    static constexpr uint8_t next_block_index(const uint8_t block_index) { return BLOCK_MOD(block_index + 1); }
752
+    static constexpr uint8_t prev_block_index(const uint8_t block_index) { return BLOCK_MOD(block_index - 1); }
658 753
 
659 754
     /**
660 755
      * Calculate the distance (not time) it takes to accelerate
@@ -679,12 +774,12 @@ class Planner {
679 774
     }
680 775
 
681 776
     /**
682
-     * Calculate the maximum allowable speed at this point, in order
683
-     * to reach 'target_velocity' using 'acceleration' within a given
777
+     * Calculate the maximum allowable speed squared at this point, in order
778
+     * to reach 'target_velocity_sqr' using 'acceleration' within a given
684 779
      * 'distance'.
685 780
      */
686
-    static float max_allowable_speed(const float &accel, const float &target_velocity, const float &distance) {
687
-      return SQRT(sq(target_velocity) - 2 * accel * distance);
781
+    static float max_allowable_speed_sqr(const float &accel, const float &target_velocity_sqr, const float &distance) {
782
+      return target_velocity_sqr - 2 * accel * distance;
688 783
     }
689 784
 
690 785
     #if ENABLED(BEZIER_JERK_CONTROL)
@@ -699,7 +794,7 @@ class Planner {
699 794
     static void calculate_trapezoid_for_block(block_t* const block, const float &entry_factor, const float &exit_factor);
700 795
 
701 796
     static void reverse_pass_kernel(block_t* const current, const block_t * const next);
702
-    static void forward_pass_kernel(const block_t * const previous, block_t* const current);
797
+    static void forward_pass_kernel(const block_t * const previous, block_t* const current, uint8_t block_index);
703 798
 
704 799
     static void reverse_pass();
705 800
     static void forward_pass();

+ 4
- 2
Marlin/src/module/planner_bezier.cpp 查看文件

@@ -194,9 +194,11 @@ void cubic_b_spline(const float position[NUM_AXIS], const float target[NUM_AXIS]
194 194
     #if HAS_UBL_AND_CURVES
195 195
       float pos[XYZ] = { bez_target[X_AXIS], bez_target[Y_AXIS], bez_target[Z_AXIS] };
196 196
       planner.apply_leveling(pos);
197
-      planner.buffer_segment(pos[X_AXIS], pos[Y_AXIS], pos[Z_AXIS], bez_target[E_AXIS], fr_mm_s, active_extruder);
197
+      if (!planner.buffer_segment(pos[X_AXIS], pos[Y_AXIS], pos[Z_AXIS], bez_target[E_AXIS], fr_mm_s, active_extruder))
198
+        break;
198 199
     #else
199
-      planner.buffer_line_kinematic(bez_target, fr_mm_s, extruder);
200
+      if (!planner.buffer_line_kinematic(bez_target, fr_mm_s, extruder))
201
+        break;
200 202
     #endif
201 203
   }
202 204
 }

+ 328
- 321
Marlin/src/module/stepper.cpp 查看文件

@@ -86,10 +86,6 @@ Stepper stepper; // Singleton
86 86
 
87 87
 block_t* Stepper::current_block = NULL;  // A pointer to the block currently being traced
88 88
 
89
-#if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
90
-  bool Stepper::abort_on_endstop_hit = false;
91
-#endif
92
-
93 89
 #if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
94 90
   bool Stepper::performing_homing = false;
95 91
 #endif
@@ -100,8 +96,10 @@ block_t* Stepper::current_block = NULL;  // A pointer to the block currently bei
100 96
 
101 97
 // private:
102 98
 
103
-uint8_t Stepper::last_direction_bits = 0;        // The next stepping-bits to be output
104
-int16_t Stepper::cleaning_buffer_counter = 0;
99
+uint8_t Stepper::last_direction_bits = 0,       // The next stepping-bits to be output
100
+        Stepper::last_movement_extruder = 0xFF; // Last movement extruder, as computed when the last movement was fetched from planner
101
+bool Stepper::abort_current_block,              // Signals to the stepper that current block should be aborted
102
+     Stepper::last_movement_non_null[NUM_AXIS]; // Last Movement in the given direction is not null, as computed when the last movement was fetched from planner
105 103
 
106 104
 #if ENABLED(X_DUAL_ENDSTOPS)
107 105
   bool Stepper::locked_x_motor = false, Stepper::locked_x2_motor = false;
@@ -118,7 +116,7 @@ int32_t Stepper::counter_X = 0,
118 116
         Stepper::counter_Z = 0,
119 117
         Stepper::counter_E = 0;
120 118
 
121
-volatile uint32_t Stepper::step_events_completed = 0; // The number of step events executed in the current block
119
+uint32_t Stepper::step_events_completed = 0; // The number of step events executed in the current block
122 120
 
123 121
 #if ENABLED(BEZIER_JERK_CONTROL)
124 122
   int32_t __attribute__((used)) Stepper::bezier_A __asm__("bezier_A");    // A coefficient in Bézier speed curve with alias for assembler
@@ -132,15 +130,16 @@ volatile uint32_t Stepper::step_events_completed = 0; // The number of step even
132 130
   bool Stepper::bezier_2nd_half;    // =false If Bézier curve has been initialized or not
133 131
 #endif
134 132
 
133
+uint32_t Stepper::nextMainISR = 0;
134
+bool Stepper::all_steps_done = false;
135
+
135 136
 #if ENABLED(LIN_ADVANCE)
136 137
 
137 138
   uint32_t Stepper::LA_decelerate_after;
138 139
 
139
-  constexpr hal_timer_t ADV_NEVER = HAL_TIMER_TYPE_MAX;
140
-
141
-  hal_timer_t Stepper::nextMainISR = 0,
142
-              Stepper::nextAdvanceISR = ADV_NEVER,
143
-              Stepper::eISR_Rate = ADV_NEVER;
140
+  constexpr uint32_t ADV_NEVER = 0xFFFFFFFF;
141
+  uint32_t Stepper::nextAdvanceISR = ADV_NEVER,
142
+           Stepper::eISR_Rate = ADV_NEVER;
144 143
   uint16_t Stepper::current_adv_steps = 0,
145 144
            Stepper::final_adv_steps,
146 145
            Stepper::max_adv_steps;
@@ -157,7 +156,7 @@ volatile uint32_t Stepper::step_events_completed = 0; // The number of step even
157 156
 
158 157
 #endif // LIN_ADVANCE
159 158
 
160
-int32_t Stepper::acceleration_time, Stepper::deceleration_time;
159
+uint32_t Stepper::acceleration_time, Stepper::deceleration_time;
161 160
 
162 161
 volatile int32_t Stepper::count_position[NUM_AXIS] = { 0 };
163 162
 volatile signed char Stepper::count_direction[NUM_AXIS] = { 1, 1, 1, 1 };
@@ -166,11 +165,11 @@ volatile signed char Stepper::count_direction[NUM_AXIS] = { 1, 1, 1, 1 };
166 165
   int32_t Stepper::counter_m[MIXING_STEPPERS];
167 166
 #endif
168 167
 
168
+uint32_t Stepper::ticks_nominal;
169 169
 uint8_t Stepper::step_loops, Stepper::step_loops_nominal;
170 170
 
171
-hal_timer_t Stepper::OCR1A_nominal;
172 171
 #if DISABLED(BEZIER_JERK_CONTROL)
173
-  hal_timer_t Stepper::acc_step_rate; // needed for deceleration start point
172
+  uint32_t Stepper::acc_step_rate; // needed for deceleration start point
174 173
 #endif
175 174
 
176 175
 volatile int32_t Stepper::endstops_trigsteps[XYZ];
@@ -185,12 +184,12 @@ volatile int32_t Stepper::endstops_trigsteps[XYZ];
185 184
   #define DUAL_ENDSTOP_APPLY_STEP(A,V)                                                                                                           \
186 185
     if (performing_homing) {                                                                                                                        \
187 186
       if (A##_HOME_DIR < 0) {                                                                                                                    \
188
-        if (!(TEST(endstops.old_endstop_bits, A##_MIN) && count_direction[_AXIS(A)] < 0) && !LOCKED_##A##_MOTOR) A##_STEP_WRITE(V);     \
189
-        if (!(TEST(endstops.old_endstop_bits, A##2_MIN) && count_direction[_AXIS(A)] < 0) && !LOCKED_##A##2_MOTOR) A##2_STEP_WRITE(V);  \
187
+        if (!(TEST(endstops.current_endstop_bits, A##_MIN) && count_direction[_AXIS(A)] < 0) && !LOCKED_##A##_MOTOR) A##_STEP_WRITE(V);     \
188
+        if (!(TEST(endstops.current_endstop_bits, A##2_MIN) && count_direction[_AXIS(A)] < 0) && !LOCKED_##A##2_MOTOR) A##2_STEP_WRITE(V);  \
190 189
       }                                                                                                                                             \
191 190
       else {                                                                                                                                        \
192
-        if (!(TEST(endstops.old_endstop_bits, A##_MAX) && count_direction[_AXIS(A)] > 0) && !LOCKED_##A##_MOTOR) A##_STEP_WRITE(V);     \
193
-        if (!(TEST(endstops.old_endstop_bits, A##2_MAX) && count_direction[_AXIS(A)] > 0) && !LOCKED_##A##2_MOTOR) A##2_STEP_WRITE(V);  \
191
+        if (!(TEST(endstops.current_endstop_bits, A##_MAX) && count_direction[_AXIS(A)] > 0) && !LOCKED_##A##_MOTOR) A##_STEP_WRITE(V);     \
192
+        if (!(TEST(endstops.current_endstop_bits, A##2_MAX) && count_direction[_AXIS(A)] > 0) && !LOCKED_##A##2_MOTOR) A##2_STEP_WRITE(V);  \
194 193
       }                                                                                                                                             \
195 194
     }                                                                                                                                               \
196 195
     else {                                                                                                                                          \
@@ -319,10 +318,6 @@ void Stepper::set_directions() {
319 318
   #endif // !LIN_ADVANCE
320 319
 }
321 320
 
322
-#if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
323
-  extern volatile uint8_t e_hit;
324
-#endif
325
-
326 321
 #if ENABLED(BEZIER_JERK_CONTROL)
327 322
   /**
328 323
    *   We are using a quintic (fifth-degree) Bézier polynomial for the velocity curve.
@@ -379,7 +374,7 @@ void Stepper::set_directions() {
379 374
    *
380 375
    *   Floating point arithmetic execution time cost is prohibitive, so we will transform the math to
381 376
    * use fixed point values to be able to evaluate it in realtime. Assuming a maximum of 250000 steps
382
-   * per second (driver pulses should at least be 2uS hi/2uS lo), and allocating 2 bits to avoid
377
+   * per second (driver pulses should at least be 2µS hi/2µS lo), and allocating 2 bits to avoid
383 378
    * overflows on the evaluation of the Bézier curve, means we can use
384 379
    *
385 380
    *   t: unsigned Q0.32 (0 <= t < 1) |range 0 to 0xFFFFFFFF unsigned
@@ -1149,11 +1144,27 @@ void Stepper::set_directions() {
1149 1144
 HAL_STEP_TIMER_ISR {
1150 1145
   HAL_timer_isr_prologue(STEP_TIMER_NUM);
1151 1146
 
1152
-  #if ENABLED(LIN_ADVANCE)
1153
-    Stepper::advance_isr_scheduler();
1154
-  #else
1155
-    Stepper::isr();
1156
-  #endif
1147
+  // Program timer compare for the maximum period, so it does NOT
1148
+  // flag an interrupt while this ISR is running - So changes from small
1149
+  // periods to big periods are respected and the timer does not reset to 0
1150
+  HAL_timer_set_compare(STEP_TIMER_NUM, HAL_TIMER_TYPE_MAX);
1151
+
1152
+  // Call the ISR scheduler
1153
+  hal_timer_t ticks = Stepper::isr_scheduler();
1154
+
1155
+  // Now 'ticks' contains the period to the next Stepper ISR.
1156
+  // Potential problem: Since the timer continues to run, the requested
1157
+  // compare value may already have passed.
1158
+  //
1159
+  // Assuming at least 6µs between calls to this ISR...
1160
+  // On AVR the ISR epilogue is estimated at 40 instructions - close to 2.5µS.
1161
+  // On ARM the ISR epilogue is estimated at 10 instructions - close to 200nS.
1162
+  // In either case leave at least 4µS for other tasks to execute.
1163
+  const hal_timer_t minticks = HAL_timer_get_count(STEP_TIMER_NUM) + hal_timer_t((HAL_TICKS_PER_US) * 4); // ISR never takes more than 1ms, so this shouldn't cause trouble
1164
+  NOLESS(ticks, MAX(minticks, hal_timer_t((STEP_TIMER_MIN_INTERVAL) * (HAL_TICKS_PER_US))));
1165
+
1166
+  // Set the next ISR to fire at the proper time
1167
+  HAL_timer_set_compare(STEP_TIMER_NUM, ticks);
1157 1168
 
1158 1169
   HAL_timer_isr_epilogue(STEP_TIMER_NUM);
1159 1170
 }
@@ -1164,168 +1175,73 @@ HAL_STEP_TIMER_ISR {
1164 1175
   #define STEP_MULTIPLY(A,B) MultiU24X32toH16(A, B)
1165 1176
 #endif
1166 1177
 
1167
-void Stepper::isr() {
1168
-
1169
-  #define ENDSTOP_NOMINAL_OCR_VAL 1500 * HAL_TICKS_PER_US // Check endstops every 1.5ms to guarantee two stepper ISRs within 5ms for BLTouch
1170
-  #define OCR_VAL_TOLERANCE        500 * HAL_TICKS_PER_US // First max delay is 2.0ms, last min delay is 0.5ms, all others 1.5ms
1171
-
1172
-  hal_timer_t ocr_val;
1173
-  static uint32_t step_remaining = 0;  // SPLIT function always runs.  This allows 16 bit timers to be
1174
-                                       // used to generate the stepper ISR.
1175
-  #define SPLIT(L) do { \
1176
-    if (L > ENDSTOP_NOMINAL_OCR_VAL) { \
1177
-      const uint32_t remainder = (uint32_t)L % (ENDSTOP_NOMINAL_OCR_VAL); \
1178
-      ocr_val = (remainder < OCR_VAL_TOLERANCE) ? ENDSTOP_NOMINAL_OCR_VAL + remainder : ENDSTOP_NOMINAL_OCR_VAL; \
1179
-      step_remaining = (uint32_t)L - ocr_val; \
1180
-    } \
1181
-    else \
1182
-      ocr_val = L;\
1183
-  }while(0)
1184
-
1185
-  // Time remaining before the next step?
1186
-  if (step_remaining) {
1187
-
1188
-    // Make sure endstops are updated
1189
-    if (ENDSTOPS_ENABLED) endstops.update();
1190
-
1191
-    // Next ISR either for endstops or stepping
1192
-    ocr_val = step_remaining <= ENDSTOP_NOMINAL_OCR_VAL ? step_remaining : ENDSTOP_NOMINAL_OCR_VAL;
1193
-    step_remaining -= ocr_val;
1194
-    _NEXT_ISR(ocr_val);
1195
-
1196
-    #if DISABLED(LIN_ADVANCE)
1197
-      HAL_timer_restrain(STEP_TIMER_NUM, STEP_TIMER_MIN_INTERVAL * HAL_TICKS_PER_US);
1198
-    #endif
1199
-
1200
-    return;
1201
-  }
1202
-
1203
-  //
1204
-  // When cleaning, discard the current block and run fast
1205
-  //
1206
-  if (cleaning_buffer_counter) {
1207
-    if (cleaning_buffer_counter < 0) {          // Count up for endstop hit
1208
-      if (current_block) planner.discard_current_block(); // Discard the active block that led to the trigger
1209
-      if (!planner.discard_continued_block())   // Discard next CONTINUED block
1210
-        cleaning_buffer_counter = 0;            // Keep discarding until non-CONTINUED
1211
-    }
1212
-    else {
1213
-      planner.discard_current_block();
1214
-      --cleaning_buffer_counter;                // Count down for abort print
1215
-      #if ENABLED(SD_FINISHED_STEPPERRELEASE) && defined(SD_FINISHED_RELEASECOMMAND)
1216
-        if (!cleaning_buffer_counter) enqueue_and_echo_commands_P(PSTR(SD_FINISHED_RELEASECOMMAND));
1217
-      #endif
1218
-    }
1219
-    current_block = NULL;                       // Prep to get a new block after cleaning
1220
-    _NEXT_ISR(HAL_STEPPER_TIMER_RATE / 10000);  // Run at max speed - 10 KHz
1221
-    return;
1222
-  }
1223
-
1224
-  // If there is no current block, attempt to pop one from the buffer
1225
-  if (!current_block) {
1226
-
1227
-    // Anything in the buffer?
1228
-    if ((current_block = planner.get_current_block())) {
1229
-
1230
-      // Sync block? Sync the stepper counts and return
1231
-      while (TEST(current_block->flag, BLOCK_BIT_SYNC_POSITION)) {
1232
-        _set_position(
1233
-          current_block->steps[A_AXIS], current_block->steps[B_AXIS],
1234
-          current_block->steps[C_AXIS], current_block->steps[E_AXIS]
1235
-        );
1236
-        planner.discard_current_block();
1237
-        if (!(current_block = planner.get_current_block())) return;
1238
-      }
1178
+hal_timer_t Stepper::isr_scheduler() {
1179
+  uint32_t interval;
1239 1180
 
1240
-      // Initialize the trapezoid generator from the current block.
1241
-      static int8_t last_extruder = -1;
1181
+  // Run main stepping pulse phase ISR if we have to
1182
+  if (!nextMainISR) Stepper::stepper_pulse_phase_isr();
1242 1183
 
1243
-      #if ENABLED(LIN_ADVANCE)
1244
-        #if E_STEPPERS > 1
1245
-          if (current_block->active_extruder != last_extruder) {
1246
-            current_adv_steps = 0; // If the now active extruder wasn't in use during the last move, its pressure is most likely gone.
1247
-            LA_active_extruder = current_block->active_extruder;
1248
-          }
1249
-        #endif
1250
-
1251
-        if ((use_advance_lead = current_block->use_advance_lead)) {
1252
-          LA_decelerate_after = current_block->decelerate_after;
1253
-          final_adv_steps = current_block->final_adv_steps;
1254
-          max_adv_steps = current_block->max_adv_steps;
1255
-        }
1256
-      #endif
1257
-
1258
-      if (current_block->direction_bits != last_direction_bits || current_block->active_extruder != last_extruder) {
1259
-        last_direction_bits = current_block->direction_bits;
1260
-        last_extruder = current_block->active_extruder;
1261
-        set_directions();
1262
-      }
1184
+  #if ENABLED(LIN_ADVANCE)
1185
+    // Run linear advance stepper ISR if we have to
1186
+    if (!nextAdvanceISR) nextAdvanceISR = Stepper::advance_isr();
1187
+  #endif
1263 1188
 
1264
-      // No acceleration / deceleration time elapsed so far
1265
-      acceleration_time = deceleration_time = 0;
1189
+  // ^== Time critical. NOTHING besides pulse generation should be above here!!!
1266 1190
 
1267
-      // No step events completed so far
1268
-      step_events_completed = 0;
1191
+  // Run main stepping block processing ISR if we have to
1192
+  if (!nextMainISR) nextMainISR = Stepper::stepper_block_phase_isr();
1269 1193
 
1270
-      // step_rate to timer interval
1271
-      OCR1A_nominal = calc_timer_interval(current_block->nominal_rate);
1194
+  #if ENABLED(LIN_ADVANCE)
1195
+    // Select the closest interval in time
1196
+    interval = (nextAdvanceISR <= nextMainISR)
1197
+      ? nextAdvanceISR
1198
+      : nextMainISR;
1272 1199
 
1273
-      // make a note of the number of step loops required at nominal speed
1274
-      step_loops_nominal = step_loops;
1200
+  #else // !ENABLED(LIN_ADVANCE)
1275 1201
 
1276
-      #if DISABLED(BEZIER_JERK_CONTROL)
1277
-        // Set as deceleration point the initial rate of the block
1278
-        acc_step_rate = current_block->initial_rate;
1279
-      #endif
1202
+    // The interval is just the remaining time to the stepper ISR
1203
+    interval = nextMainISR;
1204
+  #endif
1280 1205
 
1281
-      #if ENABLED(BEZIER_JERK_CONTROL)
1282
-        // Initialize the Bézier speed curve
1283
-        _calc_bezier_curve_coeffs(current_block->initial_rate, current_block->cruise_rate, current_block->acceleration_time_inverse);
1206
+  // Limit the value to the maximum possible value of the timer
1207
+  if (interval > HAL_TIMER_TYPE_MAX)
1208
+    interval = HAL_TIMER_TYPE_MAX;
1284 1209
 
1285
-        // We have not started the 2nd half of the trapezoid
1286
-        bezier_2nd_half = false;
1287
-      #endif
1210
+  // Compute the time remaining for the main isr
1211
+  nextMainISR -= interval;
1288 1212
 
1289
-      // Initialize Bresenham counters to 1/2 the ceiling
1290
-      counter_X = counter_Y = counter_Z = counter_E = -(current_block->step_event_count >> 1);
1291
-      #if ENABLED(MIXING_EXTRUDER)
1292
-        MIXING_STEPPERS_LOOP(i)
1293
-          counter_m[i] = -(current_block->mix_event_count[i] >> 1);
1294
-      #endif
1213
+  #if ENABLED(LIN_ADVANCE)
1214
+    // Compute the time remaining for the advance isr
1215
+    if (nextAdvanceISR != ADV_NEVER)
1216
+      nextAdvanceISR -= interval;
1217
+  #endif
1295 1218
 
1296
-      #if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
1297
-        e_hit = 2; // Needed for the case an endstop is already triggered before the new move begins.
1298
-                   // No 'change' can be detected.
1299
-      #endif
1219
+  return (hal_timer_t)interval;
1220
+}
1300 1221
 
1301
-      #if ENABLED(Z_LATE_ENABLE)
1302
-        // If delayed Z enable, postpone move for 1mS
1303
-        if (current_block->steps[Z_AXIS] > 0) {
1304
-          enable_Z();
1305
-          _NEXT_ISR(HAL_STEPPER_TIMER_RATE / 1000); // Run at slow speed - 1 KHz
1306
-          return;
1307
-        }
1308
-      #endif
1309
-    }
1310
-    else {
1311
-      // If no more queued moves, postpone next check for 1mS
1312
-      _NEXT_ISR(HAL_STEPPER_TIMER_RATE / 1000); // Run at slow speed - 1 KHz
1313
-      return;
1222
+// This part of the ISR should ONLY create the pulses for the steppers
1223
+// -- Nothing more, nothing less -- We want to avoid jitter from where
1224
+// the pulses should be generated (when the interrupt triggers) to the
1225
+// time pulses are actually created. So, PLEASE DO NOT PLACE ANY CODE
1226
+// above this line that can conditionally change that time (we are trying
1227
+// to keep the delay between the interrupt triggering and pulse generation
1228
+// as constant as possible!!!!
1229
+void Stepper::stepper_pulse_phase_isr() {
1230
+
1231
+  // If we must abort the current block, do so!
1232
+  if (abort_current_block) {
1233
+    abort_current_block = false;
1234
+    if (current_block) {
1235
+      current_block = NULL;
1236
+      planner.discard_current_block();
1314 1237
     }
1315 1238
   }
1316 1239
 
1317
-  // Update endstops state, if enabled
1318
-  #if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
1319
-    if (e_hit && ENDSTOPS_ENABLED) {
1320
-      endstops.update();
1321
-      e_hit--;
1322
-    }
1323
-  #else
1324
-    if (ENDSTOPS_ENABLED) endstops.update();
1325
-  #endif
1240
+  // If there is no current block, do nothing
1241
+  if (!current_block) return;
1326 1242
 
1327 1243
   // Take multiple steps per interrupt (For high speed moves)
1328
-  bool all_steps_done = false;
1244
+  all_steps_done = false;
1329 1245
   for (uint8_t i = step_loops; i--;) {
1330 1246
 
1331 1247
     #define _COUNTER(AXIS) counter_## AXIS
@@ -1520,116 +1436,213 @@ void Stepper::isr() {
1520 1436
     #endif
1521 1437
 
1522 1438
   } // steps_loop
1439
+}
1523 1440
 
1524
-  // Calculate new timer value
1525
-  if (step_events_completed <= (uint32_t)current_block->accelerate_until) {
1441
+// This is the last half of the stepper interrupt: This one processes and
1442
+// properly schedules blocks from the planner. This is executed after creating
1443
+// the step pulses, so it is not time critical, as pulses are already done.
1526 1444
 
1527
-    #if ENABLED(BEZIER_JERK_CONTROL)
1528
-      // Get the next speed to use (Jerk limited!)
1529
-      hal_timer_t acc_step_rate =
1530
-        acceleration_time < current_block->acceleration_time
1531
-          ? _eval_bezier_curve(acceleration_time)
1532
-          : current_block->cruise_rate;
1533
-    #else
1534
-      acc_step_rate = STEP_MULTIPLY(acceleration_time, current_block->acceleration_rate) + current_block->initial_rate;
1535
-      NOMORE(acc_step_rate, current_block->nominal_rate);
1536
-    #endif
1445
+uint32_t Stepper::stepper_block_phase_isr() {
1537 1446
 
1538
-    // step_rate to timer interval
1539
-    const hal_timer_t interval = calc_timer_interval(acc_step_rate);
1447
+  // If no queued movements, just wait 1ms for the next move
1448
+  uint32_t interval = (HAL_STEPPER_TIMER_RATE / 1000);
1540 1449
 
1541
-    SPLIT(interval);  // split step into multiple ISRs if larger than ENDSTOP_NOMINAL_OCR_VAL
1542
-    _NEXT_ISR(ocr_val);
1450
+  // If there is a current block
1451
+  if (current_block) {
1543 1452
 
1544
-    acceleration_time += interval;
1453
+    // Calculate new timer value
1454
+    if (step_events_completed <= current_block->accelerate_until) {
1545 1455
 
1546
-    #if ENABLED(LIN_ADVANCE)
1547
-      if (current_block->use_advance_lead) {
1548
-        if (step_events_completed == step_loops || (e_steps && eISR_Rate != current_block->advance_speed)) {
1549
-          nextAdvanceISR = 0; // Wake up eISR on first acceleration loop and fire ISR if final adv_rate is reached
1550
-          eISR_Rate = current_block->advance_speed;
1456
+      #if ENABLED(BEZIER_JERK_CONTROL)
1457
+        // Get the next speed to use (Jerk limited!)
1458
+        uint32_t acc_step_rate =
1459
+          acceleration_time < current_block->acceleration_time
1460
+            ? _eval_bezier_curve(acceleration_time)
1461
+            : current_block->cruise_rate;
1462
+      #else
1463
+        acc_step_rate = STEP_MULTIPLY(acceleration_time, current_block->acceleration_rate) + current_block->initial_rate;
1464
+        NOMORE(acc_step_rate, current_block->nominal_rate);
1465
+      #endif
1466
+
1467
+      // step_rate to timer interval
1468
+      interval = calc_timer_interval(acc_step_rate);
1469
+      acceleration_time += interval;
1470
+
1471
+      #if ENABLED(LIN_ADVANCE)
1472
+        if (current_block->use_advance_lead) {
1473
+          if (step_events_completed == step_loops || (e_steps && eISR_Rate != current_block->advance_speed)) {
1474
+            nextAdvanceISR = 0; // Wake up eISR on first acceleration loop and fire ISR if final adv_rate is reached
1475
+            eISR_Rate = current_block->advance_speed;
1476
+          }
1551 1477
         }
1552
-      }
1553
-      else {
1554
-        eISR_Rate = ADV_NEVER;
1555
-        if (e_steps) nextAdvanceISR = 0;
1556
-      }
1557
-    #endif // LIN_ADVANCE
1478
+        else {
1479
+          eISR_Rate = ADV_NEVER;
1480
+          if (e_steps) nextAdvanceISR = 0;
1481
+        }
1482
+      #endif // LIN_ADVANCE
1483
+    }
1484
+    else if (step_events_completed > current_block->decelerate_after) {
1485
+      uint32_t step_rate;
1486
+
1487
+      #if ENABLED(BEZIER_JERK_CONTROL)
1488
+        // If this is the 1st time we process the 2nd half of the trapezoid...
1489
+        if (!bezier_2nd_half) {
1490
+          // Initialize the Bézier speed curve
1491
+          _calc_bezier_curve_coeffs(current_block->cruise_rate, current_block->final_rate, current_block->deceleration_time_inverse);
1492
+          bezier_2nd_half = true;
1493
+        }
1494
+
1495
+        // Calculate the next speed to use
1496
+        step_rate = deceleration_time < current_block->deceleration_time
1497
+          ? _eval_bezier_curve(deceleration_time)
1498
+          : current_block->final_rate;
1499
+      #else
1500
+
1501
+        // Using the old trapezoidal control
1502
+        step_rate = STEP_MULTIPLY(deceleration_time, current_block->acceleration_rate);
1503
+        if (step_rate < acc_step_rate) { // Still decelerating?
1504
+          step_rate = acc_step_rate - step_rate;
1505
+          NOLESS(step_rate, current_block->final_rate);
1506
+        }
1507
+        else
1508
+          step_rate = current_block->final_rate;
1509
+      #endif
1510
+
1511
+      // step_rate to timer interval
1512
+      interval = calc_timer_interval(step_rate);
1513
+      deceleration_time += interval;
1514
+
1515
+      #if ENABLED(LIN_ADVANCE)
1516
+        if (current_block->use_advance_lead) {
1517
+          if (step_events_completed <= current_block->decelerate_after + step_loops || (e_steps && eISR_Rate != current_block->advance_speed)) {
1518
+            nextAdvanceISR = 0; // Wake up eISR on first deceleration loop
1519
+            eISR_Rate = current_block->advance_speed;
1520
+          }
1521
+        }
1522
+        else {
1523
+          eISR_Rate = ADV_NEVER;
1524
+          if (e_steps) nextAdvanceISR = 0;
1525
+        }
1526
+      #endif // LIN_ADVANCE
1527
+    }
1528
+    else {
1529
+
1530
+      #if ENABLED(LIN_ADVANCE)
1531
+        // If there are any esteps, fire the next advance_isr "now"
1532
+        if (e_steps && eISR_Rate != current_block->advance_speed) nextAdvanceISR = 0;
1533
+      #endif
1534
+
1535
+      // The timer interval is just the nominal value for the nominal speed
1536
+      interval = ticks_nominal;
1537
+
1538
+      // Ensure this runs at the correct step rate, even if it just came off an acceleration
1539
+      step_loops = step_loops_nominal;
1540
+    }
1541
+
1542
+    // If current block is finished, reset pointer
1543
+    if (all_steps_done) {
1544
+      current_block = NULL;
1545
+      planner.discard_current_block();
1546
+    }
1558 1547
   }
1559
-  else if (step_events_completed > (uint32_t)current_block->decelerate_after) {
1560
-    hal_timer_t step_rate;
1561 1548
 
1562
-    #if ENABLED(BEZIER_JERK_CONTROL)
1563
-      // If this is the 1st time we process the 2nd half of the trapezoid...
1564
-      if (!bezier_2nd_half) {
1549
+  // If there is no current block at this point, attempt to pop one from the buffer
1550
+  // and prepare its movement
1551
+  if (!current_block) {
1565 1552
 
1566
-        // Initialize the Bézier speed curve
1567
-        _calc_bezier_curve_coeffs(current_block->cruise_rate, current_block->final_rate, current_block->deceleration_time_inverse);
1568
-        bezier_2nd_half = true;
1553
+    // Anything in the buffer?
1554
+    if ((current_block = planner.get_current_block())) {
1555
+
1556
+      // Sync block? Sync the stepper counts and return
1557
+      while (TEST(current_block->flag, BLOCK_BIT_SYNC_POSITION)) {
1558
+        _set_position(
1559
+          current_block->position[A_AXIS], current_block->position[B_AXIS],
1560
+          current_block->position[C_AXIS], current_block->position[E_AXIS]
1561
+        );
1562
+        planner.discard_current_block();
1563
+
1564
+        // Try to get a new block
1565
+        if (!(current_block = planner.get_current_block()))
1566
+          return interval; // No more queued movements!
1569 1567
       }
1570 1568
 
1571
-      // Calculate the next speed to use
1572
-      step_rate = deceleration_time < current_block->deceleration_time
1573
-        ? _eval_bezier_curve(deceleration_time)
1574
-        : current_block->final_rate;
1575
-    #else
1569
+      // Compute movement direction for proper endstop handling
1570
+      LOOP_NA(i) last_movement_non_null[i] = !!current_block->steps[i];
1571
+
1572
+      // Initialize the trapezoid generator from the current block.
1573
+      #if ENABLED(LIN_ADVANCE)
1574
+        #if E_STEPPERS > 1
1575
+          if (current_block->active_extruder != last_movement_extruder) {
1576
+            current_adv_steps = 0; // If the now active extruder wasn't in use during the last move, its pressure is most likely gone.
1577
+            LA_active_extruder = current_block->active_extruder;
1578
+          }
1579
+        #endif
1580
+
1581
+        if ((use_advance_lead = current_block->use_advance_lead)) {
1582
+          LA_decelerate_after = current_block->decelerate_after;
1583
+          final_adv_steps = current_block->final_adv_steps;
1584
+          max_adv_steps = current_block->max_adv_steps;
1585
+        }
1586
+      #endif
1576 1587
 
1577
-      // Using the old trapezoidal control
1578
-      step_rate = STEP_MULTIPLY(deceleration_time, current_block->acceleration_rate);
1579
-      if (step_rate < acc_step_rate) { // Still decelerating?
1580
-        step_rate = acc_step_rate - step_rate;
1581
-        NOLESS(step_rate, current_block->final_rate);
1588
+      if (current_block->direction_bits != last_direction_bits || current_block->active_extruder != last_movement_extruder) {
1589
+        last_direction_bits = current_block->direction_bits;
1590
+        last_movement_extruder = current_block->active_extruder;
1591
+        set_directions();
1582 1592
       }
1583
-      else
1584
-        step_rate = current_block->final_rate;
1585 1593
 
1586
-    #endif
1594
+      // At this point, we must ensure the movement about to execute isn't
1595
+      // trying to force the head against a limit switch. If using interrupt-
1596
+      // driven change detection, and already against a limit then no call to
1597
+      // the endstop_triggered method will be done and the movement will be
1598
+      // done against the endstop. So, check the limits here: If the movement
1599
+      // is against the limits, the block will be marked as to be killed, and
1600
+      // on the next call to this ISR, will be discarded.
1601
+      endstops.check_possible_change();
1587 1602
 
1588
-    // step_rate to timer interval
1589
-    const hal_timer_t interval = calc_timer_interval(step_rate);
1603
+      // No acceleration / deceleration time elapsed so far
1604
+      acceleration_time = deceleration_time = 0;
1590 1605
 
1591
-    SPLIT(interval);  // split step into multiple ISRs if larger than ENDSTOP_NOMINAL_OCR_VAL
1592
-    _NEXT_ISR(ocr_val);
1606
+      // No step events completed so far
1607
+      step_events_completed = 0;
1593 1608
 
1594
-    deceleration_time += interval;
1609
+      // step_rate to timer interval for the nominal speed
1610
+      ticks_nominal = calc_timer_interval(current_block->nominal_rate);
1595 1611
 
1596
-    #if ENABLED(LIN_ADVANCE)
1597
-      if (current_block->use_advance_lead) {
1598
-        if (step_events_completed <= (uint32_t)current_block->decelerate_after + step_loops || (e_steps && eISR_Rate != current_block->advance_speed)) {
1599
-          nextAdvanceISR = 0; // Wake up eISR on first deceleration loop
1600
-          eISR_Rate = current_block->advance_speed;
1601
-        }
1602
-      }
1603
-      else {
1604
-        eISR_Rate = ADV_NEVER;
1605
-        if (e_steps) nextAdvanceISR = 0;
1606
-      }
1607
-    #endif // LIN_ADVANCE
1608
-  }
1609
-  else {
1612
+      // make a note of the number of step loops required at nominal speed
1613
+      step_loops_nominal = step_loops;
1610 1614
 
1611
-    #if ENABLED(LIN_ADVANCE)
1612
-      // If we have esteps to execute, fire the next advance_isr "now"
1613
-      if (e_steps && eISR_Rate != current_block->advance_speed) nextAdvanceISR = 0;
1614
-    #endif
1615
+      #if DISABLED(BEZIER_JERK_CONTROL)
1616
+        // Set as deceleration point the initial rate of the block
1617
+        acc_step_rate = current_block->initial_rate;
1618
+      #endif
1615 1619
 
1616
-    SPLIT(OCR1A_nominal);  // split step into multiple ISRs if larger than ENDSTOP_NOMINAL_OCR_VAL
1617
-    _NEXT_ISR(ocr_val);
1620
+      #if ENABLED(BEZIER_JERK_CONTROL)
1621
+        // Initialize the Bézier speed curve
1622
+        _calc_bezier_curve_coeffs(current_block->initial_rate, current_block->cruise_rate, current_block->acceleration_time_inverse);
1618 1623
 
1619
-    // ensure we're running at the correct step rate, even if we just came off an acceleration
1620
-    step_loops = step_loops_nominal;
1621
-  }
1624
+        // We have not started the 2nd half of the trapezoid
1625
+        bezier_2nd_half = false;
1626
+      #endif
1622 1627
 
1623
-  #if DISABLED(LIN_ADVANCE)
1624
-    // Make sure stepper ISR doesn't monopolize the CPU
1625
-    HAL_timer_restrain(STEP_TIMER_NUM, STEP_TIMER_MIN_INTERVAL * HAL_TICKS_PER_US);
1626
-  #endif
1628
+      // Initialize Bresenham counters to 1/2 the ceiling
1629
+      counter_X = counter_Y = counter_Z = counter_E = -((int32_t)(current_block->step_event_count >> 1));
1630
+      #if ENABLED(MIXING_EXTRUDER)
1631
+        MIXING_STEPPERS_LOOP(i)
1632
+          counter_m[i] = -(current_block->mix_event_count[i] >> 1);
1633
+      #endif
1627 1634
 
1628
-  // If current block is finished, reset pointer
1629
-  if (all_steps_done) {
1630
-    current_block = NULL;
1631
-    planner.discard_current_block();
1635
+      #if ENABLED(Z_LATE_ENABLE)
1636
+        // If delayed Z enable, enable it now. This option will severely interfere with
1637
+        //  timing between pulses when chaining motion between blocks, and it could lead
1638
+        //  to lost steps in both X and Y axis, so avoid using it unless strictly necessary!!
1639
+        if (current_block->steps[Z_AXIS]) enable_Z();
1640
+      #endif
1641
+    }
1632 1642
   }
1643
+
1644
+  // Return the interval to wait
1645
+  return interval;
1633 1646
 }
1634 1647
 
1635 1648
 #if ENABLED(LIN_ADVANCE)
@@ -1638,8 +1651,8 @@ void Stepper::isr() {
1638 1651
   #define EXTRA_CYCLES_E (STEP_PULSE_CYCLES - (CYCLES_EATEN_E))
1639 1652
 
1640 1653
   // Timer interrupt for E. e_steps is set in the main routine;
1641
-
1642
-  void Stepper::advance_isr() {
1654
+  uint32_t Stepper::advance_isr() {
1655
+    uint32_t interval;
1643 1656
 
1644 1657
     #if ENABLED(MK2_MULTIPLEXER) // For SNMM even-numbered steppers are reversed
1645 1658
       #define SET_E_STEP_DIR(INDEX) do{ if (e_steps) E0_DIR_WRITE(e_steps < 0 ? !INVERT_E## INDEX ##_DIR ^ TEST(INDEX, 0) : INVERT_E## INDEX ##_DIR ^ TEST(INDEX, 0)); }while(0)
@@ -1700,21 +1713,21 @@ void Stepper::isr() {
1700 1713
       if (step_events_completed > LA_decelerate_after && current_adv_steps > final_adv_steps) {
1701 1714
         e_steps--;
1702 1715
         current_adv_steps--;
1703
-        nextAdvanceISR = eISR_Rate;
1716
+        interval = eISR_Rate;
1704 1717
       }
1705 1718
       else if (step_events_completed < LA_decelerate_after && current_adv_steps < max_adv_steps) {
1706 1719
              //step_events_completed <= (uint32_t)current_block->accelerate_until) {
1707 1720
         e_steps++;
1708 1721
         current_adv_steps++;
1709
-        nextAdvanceISR = eISR_Rate;
1722
+        interval = eISR_Rate;
1710 1723
       }
1711 1724
       else {
1712
-        nextAdvanceISR = ADV_NEVER;
1725
+        interval = ADV_NEVER;
1713 1726
         eISR_Rate = ADV_NEVER;
1714 1727
       }
1715 1728
     }
1716 1729
     else
1717
-      nextAdvanceISR = ADV_NEVER;
1730
+      interval = ADV_NEVER;
1718 1731
 
1719 1732
     switch (LA_active_extruder) {
1720 1733
       case 0: SET_E_STEP_DIR(0); break;
@@ -1787,39 +1800,9 @@ void Stepper::isr() {
1787 1800
       #endif
1788 1801
 
1789 1802
     } // e_steps
1790
-  }
1791
-
1792
-  void Stepper::advance_isr_scheduler() {
1793
-
1794
-    // Run main stepping ISR if flagged
1795
-    if (!nextMainISR) isr();
1796
-
1797
-    // Run Advance stepping ISR if flagged
1798
-    if (!nextAdvanceISR) advance_isr();
1799
-
1800
-    // Is the next advance ISR scheduled before the next main ISR?
1801
-    if (nextAdvanceISR <= nextMainISR) {
1802
-      // Set up the next interrupt
1803
-      HAL_timer_set_compare(STEP_TIMER_NUM, nextAdvanceISR);
1804
-      // New interval for the next main ISR
1805
-      if (nextMainISR) nextMainISR -= nextAdvanceISR;
1806
-      // Will call Stepper::advance_isr on the next interrupt
1807
-      nextAdvanceISR = 0;
1808
-    }
1809
-    else {
1810
-      // The next main ISR comes first
1811
-      HAL_timer_set_compare(STEP_TIMER_NUM, nextMainISR);
1812
-      // New interval for the next advance ISR, if any
1813
-      if (nextAdvanceISR && nextAdvanceISR != ADV_NEVER)
1814
-        nextAdvanceISR -= nextMainISR;
1815
-      // Will call Stepper::isr on the next interrupt
1816
-      nextMainISR = 0;
1817
-    }
1818 1803
 
1819
-    // Make sure stepper ISR doesn't monopolize the CPU
1820
-    HAL_timer_restrain(STEP_TIMER_NUM, STEP_TIMER_MIN_INTERVAL * HAL_TICKS_PER_US);
1804
+    return interval;
1821 1805
   }
1822
-
1823 1806
 #endif // LIN_ADVANCE
1824 1807
 
1825 1808
 void Stepper::init() {
@@ -1924,9 +1907,6 @@ void Stepper::init() {
1924 1907
     if (!E_ENABLE_ON) E4_ENABLE_WRITE(HIGH);
1925 1908
   #endif
1926 1909
 
1927
-  // Init endstops and pullups
1928
-  endstops.init();
1929
-
1930 1910
   #define _STEP_INIT(AXIS) AXIS ##_STEP_INIT
1931 1911
   #define _WRITE_STEP(AXIS, HIGHLOW) AXIS ##_STEP_WRITE(HIGHLOW)
1932 1912
   #define _DISABLE(AXIS) disable_## AXIS()
@@ -2048,31 +2028,33 @@ void Stepper::_set_position(const int32_t &a, const int32_t &b, const int32_t &c
2048 2028
  * Get a stepper's position in steps.
2049 2029
  */
2050 2030
 int32_t Stepper::position(const AxisEnum axis) {
2051
-  CRITICAL_SECTION_START;
2052
-  const int32_t count_pos = count_position[axis];
2053
-  CRITICAL_SECTION_END;
2054
-  return count_pos;
2055
-}
2031
+  #ifdef __AVR__
2032
+    // Protect the access to the position. Only required for AVR, as
2033
+    //  any 32bit CPU offers atomic access to 32bit variables
2034
+    const bool was_enabled = STEPPER_ISR_ENABLED();
2035
+    if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
2036
+  #endif
2056 2037
 
2057
-void Stepper::finish_and_disable() {
2058
-  planner.synchronize();
2059
-  disable_all_steppers();
2060
-}
2038
+  int32_t v = count_position[axis];
2061 2039
 
2062
-void Stepper::quick_stop() {
2063
-  DISABLE_STEPPER_DRIVER_INTERRUPT();
2064
-  kill_current_block();
2065
-  current_block = NULL;
2066
-  cleaning_buffer_counter = 5000;
2067
-  planner.clear_block_buffer();
2068
-  ENABLE_STEPPER_DRIVER_INTERRUPT();
2069
-  #if ENABLED(ULTRA_LCD)
2070
-    planner.clear_block_buffer_runtime();
2040
+  #ifdef __AVR__
2041
+    // Reenable Stepper ISR
2042
+    if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
2071 2043
   #endif
2044
+  return v;
2072 2045
 }
2073 2046
 
2047
+// Signal endstops were triggered - This function can be called from
2048
+// an ISR context  (Temperature, Stepper or limits ISR), so we must
2049
+// be very careful here. If the interrupt being preempted was the
2050
+// Stepper ISR (this CAN happen with the endstop limits ISR) then
2051
+// when the stepper ISR resumes, we must be very sure that the movement
2052
+// is properly cancelled
2074 2053
 void Stepper::endstop_triggered(const AxisEnum axis) {
2075 2054
 
2055
+  const bool was_enabled = STEPPER_ISR_ENABLED();
2056
+  if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
2057
+
2076 2058
   #if IS_CORE
2077 2059
 
2078 2060
     endstops_trigsteps[axis] = 0.5f * (
@@ -2086,16 +2068,41 @@ void Stepper::endstop_triggered(const AxisEnum axis) {
2086 2068
 
2087 2069
   #endif // !COREXY && !COREXZ && !COREYZ
2088 2070
 
2089
-  kill_current_block();
2090
-  cleaning_buffer_counter = -1; // Discard the rest of the move
2071
+  // Discard the rest of the move if there is a current block
2072
+  quick_stop();
2073
+
2074
+  if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
2075
+}
2076
+
2077
+int32_t Stepper::triggered_position(const AxisEnum axis) {
2078
+  #ifdef __AVR__
2079
+    // Protect the access to the position. Only required for AVR, as
2080
+    //  any 32bit CPU offers atomic access to 32bit variables
2081
+    const bool was_enabled = STEPPER_ISR_ENABLED();
2082
+    if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
2083
+  #endif
2084
+
2085
+  const int32_t v = endstops_trigsteps[axis];
2086
+
2087
+  #ifdef __AVR__
2088
+    // Reenable Stepper ISR
2089
+    if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
2090
+  #endif
2091
+
2092
+  return v;
2091 2093
 }
2092 2094
 
2093 2095
 void Stepper::report_positions() {
2094
-  CRITICAL_SECTION_START;
2096
+
2097
+  // Protect the access to the position.
2098
+  const bool was_enabled = STEPPER_ISR_ENABLED();
2099
+  if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
2100
+
2095 2101
   const int32_t xpos = count_position[X_AXIS],
2096 2102
                 ypos = count_position[Y_AXIS],
2097 2103
                 zpos = count_position[Z_AXIS];
2098
-  CRITICAL_SECTION_END;
2104
+
2105
+  if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
2099 2106
 
2100 2107
   #if CORE_IS_XY || CORE_IS_XZ || IS_DELTA || IS_SCARA
2101 2108
     SERIAL_PROTOCOLPGM(MSG_COUNT_A);

+ 52
- 102
Marlin/src/module/stepper.h 查看文件

@@ -62,10 +62,6 @@ class Stepper {
62 62
 
63 63
     static block_t* current_block;  // A pointer to the block currently being traced
64 64
 
65
-    #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
66
-      static bool abort_on_endstop_hit;
67
-    #endif
68
-
69 65
     #if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
70 66
       static bool performing_homing;
71 67
     #endif
@@ -77,11 +73,12 @@ class Stepper {
77 73
       static uint32_t motor_current_setting[3];
78 74
     #endif
79 75
 
80
-    static int16_t cleaning_buffer_counter;
81
-
82 76
   private:
83 77
 
84
-    static uint8_t last_direction_bits;        // The next stepping-bits to be output
78
+    static uint8_t last_direction_bits,           // The next stepping-bits to be output
79
+                   last_movement_extruder;        // Last movement extruder, as computed when the last movement was fetched from planner
80
+    static bool abort_current_block,              // Signals to the stepper that current block should be aborted
81
+                last_movement_non_null[NUM_AXIS]; // Last Movement in the given direction is not null, as computed when the last movement was fetched from planner
85 82
 
86 83
     #if ENABLED(X_DUAL_ENDSTOPS)
87 84
       static bool locked_x_motor, locked_x2_motor;
@@ -95,7 +92,7 @@ class Stepper {
95 92
 
96 93
     // Counter variables for the Bresenham line tracer
97 94
     static int32_t counter_X, counter_Y, counter_Z, counter_E;
98
-    static volatile uint32_t step_events_completed; // The number of step events executed in the current block
95
+    static uint32_t step_events_completed; // The number of step events executed in the current block
99 96
 
100 97
     #if ENABLED(BEZIER_JERK_CONTROL)
101 98
       static int32_t bezier_A,     // A coefficient in Bézier speed curve
@@ -109,12 +106,14 @@ class Stepper {
109 106
       static bool bezier_2nd_half; // If Bézier curve has been initialized or not
110 107
     #endif
111 108
 
109
+    static uint32_t nextMainISR;   // time remaining for the next Step ISR
110
+    static bool all_steps_done;    // all steps done
111
+
112 112
     #if ENABLED(LIN_ADVANCE)
113 113
 
114 114
       static uint32_t LA_decelerate_after; // Copy from current executed block. Needed because current_block is set to NULL "too early".
115
-      static hal_timer_t nextMainISR, nextAdvanceISR, eISR_Rate;
115
+      static uint32_t nextAdvanceISR, eISR_Rate;
116 116
       static uint16_t current_adv_steps, final_adv_steps, max_adv_steps; // Copy from current executed block. Needed because current_block is set to NULL "too early".
117
-      #define _NEXT_ISR(T) nextMainISR = T
118 117
       static int8_t e_steps;
119 118
       static bool use_advance_lead;
120 119
       #if E_STEPPERS > 1
@@ -123,18 +122,14 @@ class Stepper {
123 122
         static constexpr int8_t LA_active_extruder = 0;
124 123
       #endif
125 124
 
126
-    #else // !LIN_ADVANCE
127
-
128
-      #define _NEXT_ISR(T) HAL_timer_set_compare(STEP_TIMER_NUM, T);
125
+    #endif // LIN_ADVANCE
129 126
 
130
-    #endif // !LIN_ADVANCE
131
-
132
-    static int32_t acceleration_time, deceleration_time;
127
+    static uint32_t acceleration_time, deceleration_time;
133 128
     static uint8_t step_loops, step_loops_nominal;
134 129
 
135
-    static hal_timer_t OCR1A_nominal;
130
+    static uint32_t ticks_nominal;
136 131
     #if DISABLED(BEZIER_JERK_CONTROL)
137
-      static hal_timer_t acc_step_rate; // needed for deceleration start point
132
+      static uint32_t acc_step_rate; // needed for deceleration start point
138 133
     #endif
139 134
 
140 135
     static volatile int32_t endstops_trigsteps[XYZ];
@@ -167,88 +162,53 @@ class Stepper {
167 162
     //
168 163
     Stepper() { };
169 164
 
170
-    //
171 165
     // Initialize stepper hardware
172
-    //
173 166
     static void init();
174 167
 
175
-    //
176 168
     // Interrupt Service Routines
177
-    //
178
-
179
-    static void isr();
180 169
 
181
-    #if ENABLED(LIN_ADVANCE)
182
-      static void advance_isr();
183
-      static void advance_isr_scheduler();
184
-    #endif
170
+    // The ISR scheduler
171
+    static hal_timer_t isr_scheduler();
185 172
 
186
-    //
187
-    // Set the current position in steps
188
-    //
189
-    static void _set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e);
173
+    // The stepper pulse phase ISR
174
+    static void stepper_pulse_phase_isr();
190 175
 
191
-    FORCE_INLINE static void _set_position(const AxisEnum a, const int32_t &v) { count_position[a] = v; }
176
+    // The stepper block processing phase ISR
177
+    static uint32_t stepper_block_phase_isr();
192 178
 
193
-    FORCE_INLINE static void set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e) {
194
-      planner.synchronize();
195
-      CRITICAL_SECTION_START;
196
-      _set_position(a, b, c, e);
197
-      CRITICAL_SECTION_END;
198
-    }
199
-
200
-    static void set_position(const AxisEnum a, const int32_t &v) {
201
-      planner.synchronize();
202
-      CRITICAL_SECTION_START;
203
-      count_position[a] = v;
204
-      CRITICAL_SECTION_END;
205
-    }
206
-
207
-    FORCE_INLINE static void _set_e_position(const int32_t &e) { count_position[E_AXIS] = e; }
208
-
209
-    static void set_e_position(const int32_t &e) {
210
-      planner.synchronize();
211
-      CRITICAL_SECTION_START;
212
-      count_position[E_AXIS] = e;
213
-      CRITICAL_SECTION_END;
214
-    }
215
-
216
-    //
217
-    // Set direction bits for all steppers
218
-    //
219
-    static void set_directions();
179
+    #if ENABLED(LIN_ADVANCE)
180
+      // The Linear advance stepper ISR
181
+      static uint32_t advance_isr();
182
+    #endif
220 183
 
221
-    //
222 184
     // Get the position of a stepper, in steps
223
-    //
224 185
     static int32_t position(const AxisEnum axis);
225 186
 
226
-    //
227 187
     // Report the positions of the steppers, in steps
228
-    //
229 188
     static void report_positions();
230 189
 
231
-    //
232 190
     // The stepper subsystem goes to sleep when it runs out of things to execute. Call this
233 191
     // to notify the subsystem that it is time to go to work.
234
-    //
235 192
     static void wake_up();
236 193
 
237
-    //
238
-    // Wait for moves to finish and disable all steppers
239
-    //
240
-    static void finish_and_disable();
194
+    // Quickly stop all steppers
195
+    FORCE_INLINE static void quick_stop() { abort_current_block = true; }
241 196
 
242
-    //
243
-    // Quickly stop all steppers and clear the blocks queue
244
-    //
245
-    static void quick_stop();
246
-
247
-    //
248 197
     // The direction of a single motor
249
-    //
250 198
     FORCE_INLINE static bool motor_direction(const AxisEnum axis) { return TEST(last_direction_bits, axis); }
251 199
 
200
+    // The last movement direction was not null on the specified axis. Note that motor direction is not necessarily the same.
201
+    FORCE_INLINE static bool movement_non_null(const AxisEnum axis) { return last_movement_non_null[axis]; }
202
+
203
+    // The extruder associated to the last movement
204
+    FORCE_INLINE static uint8_t movement_extruder() { return last_movement_extruder; }
205
+
206
+    // Handle a triggered endstop
207
+    static void endstop_triggered(const AxisEnum axis);
208
+
209
+    // Triggered position of an axis in steps
210
+    static int32_t triggered_position(const AxisEnum axis);
211
+
252 212
     #if HAS_DIGIPOTSS || HAS_MOTOR_CURRENT_PWM
253 213
       static void digitalPotWrite(const int16_t address, const int16_t value);
254 214
       static void digipot_current(const uint8_t driver, const int16_t current);
@@ -280,34 +240,24 @@ class Stepper {
280 240
       static void babystep(const AxisEnum axis, const bool direction); // perform a short step with a single stepper motor, outside of any convention
281 241
     #endif
282 242
 
283
-    static inline void kill_current_block() {
284
-      step_events_completed = current_block->step_event_count;
285
-    }
286
-
287
-    //
288
-    // Handle a triggered endstop
289
-    //
290
-    static void endstop_triggered(const AxisEnum axis);
291
-
292
-    //
293
-    // Triggered position of an axis in mm (not core-savvy)
294
-    //
295
-    FORCE_INLINE static float triggered_position_mm(const AxisEnum axis) {
296
-      return endstops_trigsteps[axis] * planner.steps_to_mm[axis];
297
-    }
298
-
299 243
     #if HAS_MOTOR_CURRENT_PWM
300 244
       static void refresh_motor_power();
301 245
     #endif
302 246
 
303 247
   private:
304 248
 
305
-    FORCE_INLINE static hal_timer_t calc_timer_interval(hal_timer_t step_rate) {
306
-      hal_timer_t timer;
249
+    // Set the current position in steps
250
+    static void _set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e);
251
+
252
+    // Set direction bits for all steppers
253
+    static void set_directions();
254
+
255
+    FORCE_INLINE static uint32_t calc_timer_interval(uint32_t step_rate) {
256
+      uint32_t timer;
307 257
 
308
-      NOMORE(step_rate, MAX_STEP_FREQUENCY);
258
+      NOMORE(step_rate, uint32_t(MAX_STEP_FREQUENCY));
309 259
 
310
-      // TODO: HAL: tidy this up, use condtionals_post.h
260
+      // TODO: HAL: tidy this up, use Conditionals_post.h
311 261
       #ifdef CPU_32_BIT
312 262
         #if ENABLED(DISABLE_MULTI_STEPPING)
313 263
           step_loops = 1;
@@ -344,20 +294,20 @@ class Stepper {
344 294
         timer = uint32_t(HAL_STEPPER_TIMER_RATE) / step_rate;
345 295
         NOLESS(timer, min_time_per_step); // (STEP_DOUBLER_FREQUENCY * 2 kHz - this should never happen)
346 296
       #else
347
-        NOLESS(step_rate, F_CPU / 500000);
297
+        NOLESS(step_rate, uint32_t(F_CPU / 500000U));
348 298
         step_rate -= F_CPU / 500000; // Correct for minimal speed
349 299
         if (step_rate >= (8 * 256)) { // higher step rate
350 300
           uint8_t tmp_step_rate = (step_rate & 0x00FF);
351
-          uint16_t table_address = (uint16_t)&speed_lookuptable_fast[(uint8_t)(step_rate >> 8)][0];
352
-          uint16_t gain = (uint16_t)pgm_read_word_near(table_address + 2);
301
+          uint16_t table_address = (uint16_t)&speed_lookuptable_fast[(uint8_t)(step_rate >> 8)][0],
302
+                   gain = (uint16_t)pgm_read_word_near(table_address + 2);
353 303
           timer = MultiU16X8toH16(tmp_step_rate, gain);
354 304
           timer = (uint16_t)pgm_read_word_near(table_address) - timer;
355 305
         }
356 306
         else { // lower step rates
357 307
           uint16_t table_address = (uint16_t)&speed_lookuptable_slow[0][0];
358 308
           table_address += ((step_rate) >> 1) & 0xFFFC;
359
-          timer = (uint16_t)pgm_read_word_near(table_address);
360
-          timer -= (((uint16_t)pgm_read_word_near(table_address + 2) * (uint8_t)(step_rate & 0x0007)) >> 3);
309
+          timer = (uint16_t)pgm_read_word_near(table_address)
310
+                - (((uint16_t)pgm_read_word_near(table_address + 2) * (uint8_t)(step_rate & 0x0007)) >> 3);
361 311
         }
362 312
         if (timer < 100) { // (20kHz - this should never happen)
363 313
           timer = 100;

+ 6
- 18
Marlin/src/module/temperature.cpp 查看文件

@@ -25,6 +25,7 @@
25 25
  */
26 26
 
27 27
 #include "temperature.h"
28
+#include "endstops.h"
28 29
 
29 30
 #include "../Marlin.h"
30 31
 #include "../lcd/ultralcd.h"
@@ -40,10 +41,6 @@
40 41
   #include "stepper.h"
41 42
 #endif
42 43
 
43
-#if ENABLED(ENDSTOP_INTERRUPTS_FEATURE) || ENABLED(PINS_DEBUGGING)
44
-  #include "endstops.h"
45
-#endif
46
-
47 44
 #include "printcounter.h"
48 45
 
49 46
 #if ENABLED(FILAMENT_WIDTH_SENSOR)
@@ -1085,9 +1082,7 @@ void Temperature::updateTemperaturesFromRawValues() {
1085 1082
     watchdog_reset();
1086 1083
   #endif
1087 1084
 
1088
-  CRITICAL_SECTION_START;
1089 1085
   temp_meas_ready = false;
1090
-  CRITICAL_SECTION_END;
1091 1086
 }
1092 1087
 
1093 1088
 
@@ -1727,6 +1722,7 @@ void Temperature::set_current_temp_raw() {
1727 1722
  *  - Step the babysteps value for each axis towards 0
1728 1723
  *  - For PINS_DEBUGGING, monitor and report endstop pins
1729 1724
  *  - For ENDSTOP_INTERRUPTS_FEATURE check endstops if flagged
1725
+ *  - Call planner.tick to count down its "ignore" time
1730 1726
  */
1731 1727
 HAL_TEMP_TIMER_ISR {
1732 1728
   HAL_timer_isr_prologue(TEMP_TIMER_NUM);
@@ -2247,19 +2243,11 @@ void Temperature::isr() {
2247 2243
     }
2248 2244
   #endif // BABYSTEPPING
2249 2245
 
2250
-  #if ENABLED(PINS_DEBUGGING)
2251
-    endstops.run_monitor();  // report changes in endstop status
2252
-  #endif
2253
-
2254
-  #if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
2246
+  // Poll endstops state, if required
2247
+  endstops.poll();
2255 2248
 
2256
-    extern volatile uint8_t e_hit;
2257
-
2258
-    if (e_hit && ENDSTOPS_ENABLED) {
2259
-      endstops.update();  // call endstop update routine
2260
-      e_hit--;
2261
-    }
2262
-  #endif
2249
+  // Periodically call the planner timer
2250
+  planner.tick();
2263 2251
 }
2264 2252
 
2265 2253
 #if HAS_TEMP_SENSOR

+ 1
- 2
Marlin/src/sd/cardreader.cpp 查看文件

@@ -29,7 +29,6 @@
29 29
 #include "../Marlin.h"
30 30
 #include "../lcd/ultralcd.h"
31 31
 #include "../module/planner.h"
32
-#include "../module/stepper.h"
33 32
 #include "../module/printcounter.h"
34 33
 #include "../core/language.h"
35 34
 #include "../gcode/queue.h"
@@ -983,7 +982,7 @@ void CardReader::printingHasFinished() {
983 982
     #endif
984 983
 
985 984
     #if ENABLED(SD_FINISHED_STEPPERRELEASE) && defined(SD_FINISHED_RELEASECOMMAND)
986
-      stepper.cleaning_buffer_counter = 1; // The command will fire from the Stepper ISR
985
+      planner.finish_and_disable();
987 986
     #endif
988 987
     print_job_timer.stop();
989 988
     if (print_job_timer.duration() > 60)

正在加载...
取消
保存