Browse Source

[2.0.x] Small assorted collection of fixes and improvements (#10911)

* Misc fixes and improvements

- Get rid of most critical sections on the Serial port drivers for AVR and DUE. Proper usage of FIFOs should allow interrupts to stay enabled without harm to queuing and dequeuing.
  Also, with 8-bit indices (for AVR) and up to 32-bit indices (for ARM), there is no need to protect reads and writes to those indices.
- Simplify the XON/XOFF logic quite a bit. Much cleaner now (both for AVR and ARM)
- Prevent a race condition (edge case) that could happen when estimating the proper value for the stepper timer (by reading it) and writing the calculated value for the time to the next ISR by disabling interrupts in those critical and small sections of the code - The problem could lead to lost steps.
- Fix dual endstops not properly homing bug (maybe).

* Set position immediately when possible
Eduardo José Tagle 7 years ago
parent
commit
d3c02410a8

+ 4
- 3
Marlin/src/HAL/HAL_AVR/HAL.h View File

@@ -64,7 +64,9 @@
64 64
   #define CRITICAL_SECTION_START  unsigned char _sreg = SREG; cli();
65 65
   #define CRITICAL_SECTION_END    SREG = _sreg;
66 66
 #endif
67
-
67
+#define ISRS_ENABLED() TEST(SREG, SREG_I)
68
+#define ENABLE_ISRS()  sei()
69
+#define DISABLE_ISRS() cli()
68 70
 
69 71
 // On AVR this is in math.h?
70 72
 //#define square(x) ((x)*(x))
@@ -181,7 +183,6 @@ void TIMER1_COMPA_vect (void) { \
181 183
     A("lds r16, %[timsk1]")            /* 2 Load into R0 the stepper timer Interrupt mask register [TIMSK1] */ \
182 184
     A("andi r16,~%[msk1]")             /* 1 Disable the stepper ISR */ \
183 185
     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 186
     A("push r16")                      /* 2 Save TIMSK1 into stack */ \
186 187
     A("in r16, 0x3B")                  /* 1 Get RAMPZ register */ \
187 188
     A("push r16")                      /* 2 Save RAMPZ into stack */ \
@@ -291,7 +292,7 @@ void TIMER0_COMPB_vect (void) { \
291 292
     A("out 0x3B, r16")                  /* 1 Restore RAMPZ register to its original value */ \
292 293
     A("pop r16")                        /* 2 Get the original TIMSK0 value but with temperature ISR disabled */ \
293 294
     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("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 296
     A("sts %[timsk0], r16")             /* 2 And restore the old value */ \
296 297
     A("pop r16")                        /* 2 Get the old SREG */ \
297 298
     A("out __SREG__, r16")              /* 1 And restore the SREG value */ \

+ 128
- 101
Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp View File

@@ -69,8 +69,6 @@
69 69
     uint8_t xon_xoff_state = XON_XOFF_CHAR_SENT | XON_CHAR;
70 70
   #endif
71 71
 
72
-  void clear_command_queue();
73
-
74 72
   #if ENABLED(SERIAL_STATS_DROPPED_RX)
75 73
     uint8_t rx_dropped_bytes = 0;
76 74
   #endif
@@ -79,10 +77,14 @@
79 77
     ring_buffer_pos_t rx_max_enqueued = 0;
80 78
   #endif
81 79
 
80
+  // A SW memory barrier, to ensure GCC does not overoptimize loops
81
+  #define sw_barrier() asm volatile("": : :"memory");
82
+
82 83
   #if ENABLED(EMERGENCY_PARSER)
83 84
     #include "../../feature/emergency_parser.h"
84 85
   #endif
85 86
 
87
+  // (called with RX interrupts disabled)
86 88
   FORCE_INLINE void store_rxd_char() {
87 89
 
88 90
     #if ENABLED(EMERGENCY_PARSER)
@@ -129,18 +131,22 @@
129 131
         // let the host react and stop sending bytes. This translates to 13mS
130 132
         // propagation time.
131 133
         if (rx_count >= (RX_BUFFER_SIZE) / 8) {
134
+
132 135
           // If TX interrupts are disabled and data register is empty,
133 136
           // just write the byte to the data register and be done. This
134 137
           // shortcut helps significantly improve the effective datarate
135 138
           // at high (>500kbit/s) bitrates, where interrupt overhead
136 139
           // becomes a slowdown.
137 140
           if (!TEST(M_UCSRxB, M_UDRIEx) && TEST(M_UCSRxA, M_UDREx)) {
141
+
138 142
             // Send an XOFF character
139 143
             M_UDRx = XOFF_CHAR;
144
+
140 145
             // clear the TXC bit -- "can be cleared by writing a one to its bit
141 146
             // location". This makes sure flush() won't return until the bytes
142 147
             // actually got written
143 148
             SBI(M_UCSRxA, M_TXCx);
149
+
144 150
             // And remember it was sent
145 151
             xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT;
146 152
           }
@@ -153,8 +159,14 @@
153 159
               xon_xoff_state = XOFF_CHAR;
154 160
             #else
155 161
               // We are not using TX interrupts, we will have to send this manually
156
-              while (!TEST(M_UCSRxA, M_UDREx)) { /* nada */ };
162
+              while (!TEST(M_UCSRxA, M_UDREx)) sw_barrier();
157 163
               M_UDRx = XOFF_CHAR;
164
+
165
+              // clear the TXC bit -- "can be cleared by writing a one to its bit
166
+              // location". This makes sure flush() won't return until the bytes
167
+              // actually got written
168
+              SBI(M_UCSRxA, M_TXCx);
169
+
158 170
               // And remember we already sent it
159 171
               xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT;
160 172
             #endif
@@ -170,6 +182,7 @@
170 182
 
171 183
   #if TX_BUFFER_SIZE > 0
172 184
 
185
+    // (called with TX irqs disabled)
173 186
     FORCE_INLINE void _tx_udr_empty_irq(void) {
174 187
       // If interrupts are enabled, there must be more data in the output
175 188
       // buffer.
@@ -251,116 +264,139 @@
251 264
     CBI(M_UCSRxB, M_UDRIEx);
252 265
   }
253 266
 
254
-  void MarlinSerial::checkRx(void) {
255
-    if (TEST(M_UCSRxA, M_RXCx)) {
256
-      CRITICAL_SECTION_START;
257
-        store_rxd_char();
258
-      CRITICAL_SECTION_END;
259
-    }
260
-  }
261
-
262 267
   int MarlinSerial::peek(void) {
263
-    CRITICAL_SECTION_START;
268
+    #if RX_BUFFER_SIZE > 256
269
+      // Disable RX interrupts, but only if non atomic reads
270
+      const bool isr_enabled = TEST(M_UCSRxB, M_RXCIEx);
271
+      CBI(M_UCSRxB, M_RXCIEx);
272
+    #endif
264 273
       const int v = rx_buffer.head == rx_buffer.tail ? -1 : rx_buffer.buffer[rx_buffer.tail];
265
-    CRITICAL_SECTION_END;
274
+    #if RX_BUFFER_SIZE > 256
275
+      // Reenable RX interrupts if they were enabled
276
+      if (isr_enabled) SBI(M_UCSRxB, M_RXCIEx);
277
+    #endif
266 278
     return v;
267 279
   }
268 280
 
269 281
   int MarlinSerial::read(void) {
270 282
     int v;
271
-    CRITICAL_SECTION_START;
272
-      const ring_buffer_pos_t t = rx_buffer.tail;
273
-      if (rx_buffer.head == t)
274
-        v = -1;
275
-      else {
276
-        v = rx_buffer.buffer[t];
277
-        rx_buffer.tail = (ring_buffer_pos_t)(t + 1) & (RX_BUFFER_SIZE - 1);
278
-
279
-        #if ENABLED(SERIAL_XON_XOFF)
280
-          if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
281
-            // Get count of bytes in the RX buffer
282
-            ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
283
-            // When below 10% of RX buffer capacity, send XON before
284
-            // running out of RX buffer bytes
285
-            if (rx_count < (RX_BUFFER_SIZE) / 10) {
286
-              xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
287
-              CRITICAL_SECTION_END;       // End critical section before returning!
288
-              writeNoHandshake(XON_CHAR);
289
-              return v;
290
-            }
283
+
284
+    #if RX_BUFFER_SIZE > 256
285
+      // Disable RX interrupts to ensure atomic reads
286
+      const bool isr_enabled = TEST(M_UCSRxB, M_RXCIEx);
287
+      CBI(M_UCSRxB, M_RXCIEx);
288
+    #endif
289
+
290
+    const ring_buffer_pos_t h = rx_buffer.head;
291
+
292
+    #if RX_BUFFER_SIZE > 256
293
+      // End critical section
294
+      if (isr_enabled) SBI(M_UCSRxB, M_RXCIEx);
295
+    #endif
296
+
297
+    ring_buffer_pos_t t = rx_buffer.tail;
298
+
299
+    if (h == t)
300
+      v = -1;
301
+    else {
302
+      v = rx_buffer.buffer[t];
303
+      t = (ring_buffer_pos_t)(t + 1) & (RX_BUFFER_SIZE - 1);
304
+
305
+      #if RX_BUFFER_SIZE > 256
306
+        // Disable RX interrupts to ensure atomic write to tail, so
307
+        // the RX isr can't read partially updated values
308
+        const bool isr_enabled = TEST(M_UCSRxB, M_RXCIEx);
309
+        CBI(M_UCSRxB, M_RXCIEx);
310
+      #endif
311
+
312
+      // Advance tail
313
+      rx_buffer.tail = t;
314
+
315
+      #if RX_BUFFER_SIZE > 256
316
+        // End critical section
317
+        if (isr_enabled) SBI(M_UCSRxB, M_RXCIEx);
318
+      #endif
319
+
320
+      #if ENABLED(SERIAL_XON_XOFF)
321
+        if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
322
+
323
+          // Get count of bytes in the RX buffer
324
+          ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
325
+
326
+          // When below 10% of RX buffer capacity, send XON before
327
+          // running out of RX buffer bytes
328
+          if (rx_count < (RX_BUFFER_SIZE) / 10) {
329
+            xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
330
+            write(XON_CHAR);
331
+            return v;
291 332
           }
292
-        #endif
293
-      }
294
-    CRITICAL_SECTION_END;
333
+        }
334
+      #endif
335
+    }
336
+
295 337
     return v;
296 338
   }
297 339
 
298 340
   ring_buffer_pos_t MarlinSerial::available(void) {
299
-    CRITICAL_SECTION_START;
341
+    #if RX_BUFFER_SIZE > 256
342
+      const bool isr_enabled = TEST(M_UCSRxB, M_RXCIEx);
343
+      CBI(M_UCSRxB, M_RXCIEx);
344
+    #endif
345
+
300 346
       const ring_buffer_pos_t h = rx_buffer.head, t = rx_buffer.tail;
301
-    CRITICAL_SECTION_END;
347
+
348
+    #if RX_BUFFER_SIZE > 256
349
+      if (isr_enabled) SBI(M_UCSRxB, M_RXCIEx);
350
+    #endif
351
+
302 352
     return (ring_buffer_pos_t)(RX_BUFFER_SIZE + h - t) & (RX_BUFFER_SIZE - 1);
303 353
   }
304 354
 
305 355
   void MarlinSerial::flush(void) {
306
-    // Don't change this order of operations. If the RX interrupt occurs between
307
-    // reading rx_buffer_head and updating rx_buffer_tail, the previous rx_buffer_head
308
-    // may be written to rx_buffer_tail, making the buffer appear full rather than empty.
309
-    CRITICAL_SECTION_START;
310
-      rx_buffer.head = rx_buffer.tail = 0;
311
-      clear_command_queue();
312
-    CRITICAL_SECTION_END;
356
+    #if RX_BUFFER_SIZE > 256
357
+      const bool isr_enabled = TEST(M_UCSRxB, M_RXCIEx);
358
+      CBI(M_UCSRxB, M_RXCIEx);
359
+    #endif
360
+
361
+      rx_buffer.tail = rx_buffer.head;
362
+
363
+    #if RX_BUFFER_SIZE > 256
364
+      if (isr_enabled) SBI(M_UCSRxB, M_RXCIEx);
365
+    #endif
313 366
 
314 367
     #if ENABLED(SERIAL_XON_XOFF)
315 368
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
316 369
         xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
317
-        writeNoHandshake(XON_CHAR);
370
+        write(XON_CHAR);
318 371
       }
319 372
     #endif
320 373
   }
321 374
 
322 375
   #if TX_BUFFER_SIZE > 0
323
-    uint8_t MarlinSerial::availableForWrite(void) {
324
-      CRITICAL_SECTION_START;
325
-        const uint8_t h = tx_buffer.head, t = tx_buffer.tail;
326
-      CRITICAL_SECTION_END;
327
-      return (uint8_t)(TX_BUFFER_SIZE + h - t) & (TX_BUFFER_SIZE - 1);
328
-    }
329
-
330 376
     void MarlinSerial::write(const uint8_t c) {
331
-      #if ENABLED(SERIAL_XON_XOFF)
332
-        const uint8_t state = xon_xoff_state;
333
-        if (!(state & XON_XOFF_CHAR_SENT)) {
334
-          // Send 2 chars: XON/XOFF, then a user-specified char
335
-          writeNoHandshake(state & XON_XOFF_CHAR_MASK);
336
-          xon_xoff_state = state | XON_XOFF_CHAR_SENT;
337
-        }
338
-      #endif
339
-      writeNoHandshake(c);
340
-    }
341
-
342
-    void MarlinSerial::writeNoHandshake(const uint8_t c) {
343 377
       _written = true;
344
-      CRITICAL_SECTION_START;
345
-        bool emty = (tx_buffer.head == tx_buffer.tail);
346
-      CRITICAL_SECTION_END;
347
-      // If the buffer and the data register is empty, just write the byte
348
-      // to the data register and be done. This shortcut helps
349
-      // significantly improve the effective datarate at high (>
350
-      // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown.
351
-      if (emty && TEST(M_UCSRxA, M_UDREx)) {
352
-        CRITICAL_SECTION_START;
353
-          M_UDRx = c;
354
-          SBI(M_UCSRxA, M_TXCx);
355
-        CRITICAL_SECTION_END;
378
+
379
+      // If the TX interrupts are disabled and the data register
380
+      // is empty, just write the byte to the data register and
381
+      // be done. This shortcut helps significantly improve the
382
+      // effective datarate at high (>500kbit/s) bitrates, where
383
+      // interrupt overhead becomes a slowdown.
384
+      if (!TEST(M_UCSRxB, M_UDRIEx) && TEST(M_UCSRxA, M_UDREx)) {
385
+        M_UDRx = c;
386
+
387
+        // clear the TXC bit -- "can be cleared by writing a one to its bit
388
+        // location". This makes sure flush() won't return until the bytes
389
+        // actually got written
390
+        SBI(M_UCSRxA, M_TXCx);
356 391
         return;
357 392
       }
393
+
358 394
       const uint8_t i = (tx_buffer.head + 1) & (TX_BUFFER_SIZE - 1);
359 395
 
360 396
       // If the output buffer is full, there's nothing for it other than to
361 397
       // wait for the interrupt handler to empty it a bit
362 398
       while (i == tx_buffer.tail) {
363
-        if (!TEST(SREG, SREG_I)) {
399
+        if (!ISRS_ENABLED()) {
364 400
           // Interrupts are disabled, so we'll have to poll the data
365 401
           // register empty flag ourselves. If it is set, pretend an
366 402
           // interrupt has happened and call the handler to free up
@@ -368,17 +404,18 @@
368 404
           if (TEST(M_UCSRxA, M_UDREx))
369 405
             _tx_udr_empty_irq();
370 406
         }
371
-        else {
372
-          // nop, the interrupt handler will free up space for us
373
-        }
407
+        // (else , the interrupt handler will free up space for us)
408
+
409
+        // Make sure compiler rereads tx_buffer.tail
410
+        sw_barrier();
374 411
       }
375 412
 
413
+      // Store new char. head is always safe to move
376 414
       tx_buffer.buffer[tx_buffer.head] = c;
377
-      { CRITICAL_SECTION_START;
378
-          tx_buffer.head = i;
379
-          SBI(M_UCSRxB, M_UDRIEx);
380
-        CRITICAL_SECTION_END;
381
-      }
415
+      tx_buffer.head = i;
416
+
417
+      // Enable TX isr
418
+      SBI(M_UCSRxB, M_UDRIEx);
382 419
       return;
383 420
     }
384 421
 
@@ -391,33 +428,23 @@
391 428
         return;
392 429
 
393 430
       while (TEST(M_UCSRxB, M_UDRIEx) || !TEST(M_UCSRxA, M_TXCx)) {
394
-        if (!TEST(SREG, SREG_I) && TEST(M_UCSRxB, M_UDRIEx))
431
+        if (!ISRS_ENABLED()) {
395 432
           // Interrupts are globally disabled, but the DR empty
396 433
           // interrupt should be enabled, so poll the DR empty flag to
397 434
           // prevent deadlock
398 435
           if (TEST(M_UCSRxA, M_UDREx))
399 436
             _tx_udr_empty_irq();
437
+        }
438
+        sw_barrier();
400 439
       }
401 440
       // If we get here, nothing is queued anymore (DRIE is disabled) and
402
-      // the hardware finished tranmission (TXC is set).
441
+      // the hardware finished transmission (TXC is set).
403 442
     }
404 443
 
405 444
   #else // TX_BUFFER_SIZE == 0
406 445
 
407 446
     void MarlinSerial::write(const uint8_t c) {
408
-      #if ENABLED(SERIAL_XON_XOFF)
409
-        // Do a priority insertion of an XON/XOFF char, if needed.
410
-        const uint8_t state = xon_xoff_state;
411
-        if (!(state & XON_XOFF_CHAR_SENT)) {
412
-          writeNoHandshake(state & XON_XOFF_CHAR_MASK);
413
-          xon_xoff_state = state | XON_XOFF_CHAR_SENT;
414
-        }
415
-      #endif
416
-      writeNoHandshake(c);
417
-    }
418
-
419
-    void MarlinSerial::writeNoHandshake(const uint8_t c) {
420
-      while (!TEST(M_UCSRxA, M_UDREx)) { /* nada */ }
447
+      while (!TEST(M_UCSRxA, M_UDREx)) sw_barrier();
421 448
       M_UDRx = c;
422 449
     }
423 450
 

+ 1
- 4
Marlin/src/HAL/HAL_AVR/MarlinSerial.h View File

@@ -94,7 +94,7 @@
94 94
     extern ring_buffer_pos_t rx_max_enqueued;
95 95
   #endif
96 96
 
97
-  class MarlinSerial { //: public Stream
97
+  class MarlinSerial {
98 98
 
99 99
     public:
100 100
       MarlinSerial() {};
@@ -104,13 +104,10 @@
104 104
       static int read(void);
105 105
       static void flush(void);
106 106
       static ring_buffer_pos_t available(void);
107
-      static void checkRx(void);
108 107
       static void write(const uint8_t c);
109 108
       #if TX_BUFFER_SIZE > 0
110
-        static uint8_t availableForWrite(void);
111 109
         static void flushTX(void);
112 110
       #endif
113
-      static void writeNoHandshake(const uint8_t c);
114 111
 
115 112
       #if ENABLED(SERIAL_STATS_DROPPED_RX)
116 113
         FORCE_INLINE static uint32_t dropped() { return rx_dropped_bytes; }

+ 5
- 2
Marlin/src/HAL/HAL_DUE/HAL.h View File

@@ -55,8 +55,11 @@
55 55
   #define analogInputToDigitalPin(p) ((p < 12u) ? (p) + 54u : -1)
56 56
 #endif
57 57
 
58
-#define CRITICAL_SECTION_START  uint32_t primask = __get_PRIMASK(); __disable_irq();
59
-#define CRITICAL_SECTION_END    if (!primask) __enable_irq();
58
+#define CRITICAL_SECTION_START  uint32_t primask = __get_PRIMASK(); __disable_irq()
59
+#define CRITICAL_SECTION_END    if (!primask) __enable_irq()
60
+#define ISRS_ENABLED() (!__get_PRIMASK())
61
+#define ENABLE_ISRS()  __enable_irq()
62
+#define DISABLE_ISRS() __disable_irq()
60 63
 
61 64
 // On AVR this is in math.h?
62 65
 #define square(x) ((x)*(x))

+ 41
- 86
Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp View File

@@ -154,12 +154,14 @@
154 154
         // let the host react and stop sending bytes. This translates to 13mS
155 155
         // propagation time.
156 156
         if (rx_count >= (RX_BUFFER_SIZE) / 8) {
157
+          
157 158
           // If TX interrupts are disabled and data register is empty,
158 159
           // just write the byte to the data register and be done. This
159 160
           // shortcut helps significantly improve the effective datarate
160 161
           // at high (>500kbit/s) bitrates, where interrupt overhead
161 162
           // becomes a slowdown.
162 163
           if (!(HWUART->UART_IMR & UART_IMR_TXRDY) && (HWUART->UART_SR & UART_SR_TXRDY)) {
164
+            
163 165
             // Send an XOFF character
164 166
             HWUART->UART_THR = XOFF_CHAR;
165 167
 
@@ -175,8 +177,9 @@
175 177
               xon_xoff_state = XOFF_CHAR;
176 178
             #else
177 179
               // We are not using TX interrupts, we will have to send this manually
178
-              while (!(HWUART->UART_SR & UART_SR_TXRDY)) { sw_barrier(); };
180
+              while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
179 181
               HWUART->UART_THR = XOFF_CHAR;
182
+              
180 183
               // And remember we already sent it
181 184
               xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT;
182 185
             #endif
@@ -303,116 +306,81 @@
303 306
     pmc_disable_periph_clk( HWUART_IRQ_ID );
304 307
   }
305 308
 
306
-  void MarlinSerial::checkRx(void) {
307
-    if (HWUART->UART_SR & UART_SR_RXRDY) {
308
-      CRITICAL_SECTION_START;
309
-      store_rxd_char();
310
-      CRITICAL_SECTION_END;
311
-    }
312
-  }
313
-
314 309
   int MarlinSerial::peek(void) {
315
-    CRITICAL_SECTION_START;
316 310
     const int v = rx_buffer.head == rx_buffer.tail ? -1 : rx_buffer.buffer[rx_buffer.tail];
317
-    CRITICAL_SECTION_END;
318 311
     return v;
319 312
   }
320 313
 
321 314
   int MarlinSerial::read(void) {
322 315
     int v;
323
-    CRITICAL_SECTION_START;
324
-    const ring_buffer_pos_t t = rx_buffer.tail;
325
-    if (rx_buffer.head == t)
316
+    
317
+    const ring_buffer_pos_t h = rx_buffer.head;
318
+    ring_buffer_pos_t t = rx_buffer.tail;
319
+    
320
+    if (h == t)
326 321
       v = -1;
327 322
     else {
328 323
       v = rx_buffer.buffer[t];
329
-      rx_buffer.tail = (ring_buffer_pos_t)(t + 1) & (RX_BUFFER_SIZE - 1);
324
+      t = (ring_buffer_pos_t)(t + 1) & (RX_BUFFER_SIZE - 1);
325
+      
326
+      // Advance tail
327
+      rx_buffer.tail = t;
330 328
 
331 329
       #if ENABLED(SERIAL_XON_XOFF)
332 330
         if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
331
+          
333 332
           // Get count of bytes in the RX buffer
334
-          ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
333
+          ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
334
+          
335 335
           // When below 10% of RX buffer capacity, send XON before
336 336
           // running out of RX buffer bytes
337 337
           if (rx_count < (RX_BUFFER_SIZE) / 10) {
338 338
             xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
339
-            CRITICAL_SECTION_END;       // End critical section before returning!
340
-            writeNoHandshake(XON_CHAR);
339
+            write(XON_CHAR);
341 340
             return v;
342 341
           }
343 342
         }
344 343
       #endif
345 344
     }
346
-    CRITICAL_SECTION_END;
347 345
     return v;
348 346
   }
349 347
 
350 348
   ring_buffer_pos_t MarlinSerial::available(void) {
351
-    CRITICAL_SECTION_START;
352 349
     const ring_buffer_pos_t h = rx_buffer.head, t = rx_buffer.tail;
353
-    CRITICAL_SECTION_END;
354 350
     return (ring_buffer_pos_t)(RX_BUFFER_SIZE + h - t) & (RX_BUFFER_SIZE - 1);
355 351
   }
356 352
 
357 353
   void MarlinSerial::flush(void) {
358
-    // Don't change this order of operations. If the RX interrupt occurs between
359
-    // reading rx_buffer_head and updating rx_buffer_tail, the previous rx_buffer_head
360
-    // may be written to rx_buffer_tail, making the buffer appear full rather than empty.
361
-    CRITICAL_SECTION_START;
362
-    rx_buffer.head = rx_buffer.tail;
363
-    CRITICAL_SECTION_END;
354
+    rx_buffer.tail = rx_buffer.head;
364 355
 
365 356
     #if ENABLED(SERIAL_XON_XOFF)
366 357
       if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
367 358
         xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
368
-        writeNoHandshake(XON_CHAR);
359
+        write(XON_CHAR);
369 360
       }
370 361
     #endif
371 362
   }
372 363
 
373 364
   #if TX_BUFFER_SIZE > 0
374
-
375
-    uint8_t MarlinSerial::availableForWrite(void) {
376
-      CRITICAL_SECTION_START;
377
-      const uint8_t h = tx_buffer.head, t = tx_buffer.tail;
378
-      CRITICAL_SECTION_END;
379
-      return (uint8_t)(TX_BUFFER_SIZE + h - t) & (TX_BUFFER_SIZE - 1);
380
-    }
381
-
382 365
     void MarlinSerial::write(const uint8_t c) {
383
-      #if ENABLED(SERIAL_XON_XOFF)
384
-        const uint8_t state = xon_xoff_state;
385
-        if (!(state & XON_XOFF_CHAR_SENT)) {
386
-          // Send 2 chars: XON/XOFF, then a user-specified char
387
-          writeNoHandshake(state & XON_XOFF_CHAR_MASK);
388
-          xon_xoff_state = state | XON_XOFF_CHAR_SENT;
389
-        }
390
-      #endif
391
-      writeNoHandshake(c);
392
-    }
393
-
394
-    void MarlinSerial::writeNoHandshake(const uint8_t c) {
395 366
       _written = true;
396
-      CRITICAL_SECTION_START;
397
-      bool emty = (tx_buffer.head == tx_buffer.tail);
398
-      CRITICAL_SECTION_END;
399
-      // If the buffer and the data register is empty, just write the byte
400
-      // to the data register and be done. This shortcut helps
401
-      // significantly improve the effective datarate at high (>
402
-      // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown.
403
-      if (emty && (HWUART->UART_SR & UART_SR_TXRDY)) {
404
-        CRITICAL_SECTION_START;
405
-          HWUART->UART_THR = c;
406
-          HWUART->UART_IER = UART_IER_TXRDY;
407
-        CRITICAL_SECTION_END;
367
+      
368
+      // If the TX interrupts are disabled and the data register 
369
+      // is empty, just write the byte to the data register and 
370
+      // be done. This shortcut helps significantly improve the 
371
+      // effective datarate at high (>500kbit/s) bitrates, where 
372
+      // interrupt overhead becomes a slowdown.
373
+      if (!(HWUART->UART_IMR & UART_IMR_TXRDY) && (HWUART->UART_SR & UART_SR_TXRDY)) {
374
+        HWUART->UART_THR = c;
408 375
         return;
409 376
       }
377
+      
410 378
       const uint8_t i = (tx_buffer.head + 1) & (TX_BUFFER_SIZE - 1);
411 379
 
412 380
       // If the output buffer is full, there's nothing for it other than to
413 381
       // wait for the interrupt handler to empty it a bit
414 382
       while (i == tx_buffer.tail) {
415
-        if (__get_PRIMASK()) {
383
+        if (!ISRS_ENABLED()) {
416 384
           // Interrupts are disabled, so we'll have to poll the data
417 385
           // register empty flag ourselves. If it is set, pretend an
418 386
           // interrupt has happened and call the handler to free up
@@ -420,31 +388,30 @@
420 388
           if (HWUART->UART_SR & UART_SR_TXRDY)
421 389
             _tx_thr_empty_irq();
422 390
         }
423
-        else {
424
-          // nop, the interrupt handler will free up space for us
425
-        }
391
+        // (else , the interrupt handler will free up space for us)
392
+        
393
+        // Make sure compiler rereads tx_buffer.tail
426 394
         sw_barrier();
427 395
       }
428 396
 
429 397
       tx_buffer.buffer[tx_buffer.head] = c;
430
-      { CRITICAL_SECTION_START;
431
-          tx_buffer.head = i;
432
-          HWUART->UART_IER = UART_IER_TXRDY;
433
-        CRITICAL_SECTION_END;
434
-      }
398
+      tx_buffer.head = i;
399
+      
400
+      // Enable TX isr
401
+      HWUART->UART_IER = UART_IER_TXRDY;
435 402
       return;
436 403
     }
437 404
 
438 405
     void MarlinSerial::flushTX(void) {
439 406
       // TX
440 407
       // If we have never written a byte, no need to flush.
441
-      if (!_written)
442
-        return;
408
+      if (!_written) return;
443 409
 
444 410
       while ((HWUART->UART_IMR & UART_IMR_TXRDY) || !(HWUART->UART_SR & UART_SR_TXEMPTY)) {
445
-        if (__get_PRIMASK())
446
-          if ((HWUART->UART_SR & UART_SR_TXRDY))
411
+        if (!ISRS_ENABLED()) {
412
+          if (HWUART->UART_SR & UART_SR_TXRDY)
447 413
             _tx_thr_empty_irq();
414
+        }
448 415
         sw_barrier();
449 416
       }
450 417
       // If we get here, nothing is queued anymore (TX interrupts are disabled) and
@@ -454,19 +421,7 @@
454 421
   #else // TX_BUFFER_SIZE == 0
455 422
 
456 423
     void MarlinSerial::write(const uint8_t c) {
457
-      #if ENABLED(SERIAL_XON_XOFF)
458
-        // Do a priority insertion of an XON/XOFF char, if needed.
459
-        const uint8_t state = xon_xoff_state;
460
-        if (!(state & XON_XOFF_CHAR_SENT)) {
461
-          writeNoHandshake(state & XON_XOFF_CHAR_MASK);
462
-          xon_xoff_state = state | XON_XOFF_CHAR_SENT;
463
-        }
464
-      #endif
465
-      writeNoHandshake(c);
466
-    }
467
-
468
-    void MarlinSerial::writeNoHandshake(const uint8_t c) {
469
-      while (!(HWUART->UART_SR & UART_SR_TXRDY)) { sw_barrier(); };
424
+      while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
470 425
       HWUART->UART_THR = c;
471 426
     }
472 427
 

+ 0
- 3
Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h View File

@@ -84,13 +84,10 @@ public:
84 84
   static int read(void);
85 85
   static void flush(void);
86 86
   static ring_buffer_pos_t available(void);
87
-  static void checkRx(void);
88 87
   static void write(const uint8_t c);
89 88
   #if TX_BUFFER_SIZE > 0
90
-    static uint8_t availableForWrite(void);
91 89
     static void flushTX(void);
92 90
   #endif
93
-  static void writeNoHandshake(const uint8_t c);
94 91
 
95 92
   #if ENABLED(SERIAL_STATS_DROPPED_RX)
96 93
     FORCE_INLINE static uint32_t dropped() { return rx_dropped_bytes; }

+ 5
- 2
Marlin/src/HAL/HAL_LPC1768/HAL.h View File

@@ -120,8 +120,11 @@ extern HalSerial usb_serial;
120 120
   #define NUM_SERIAL 1
121 121
 #endif
122 122
 
123
-#define CRITICAL_SECTION_START  uint32_t primask = __get_PRIMASK(); __disable_irq();
124
-#define CRITICAL_SECTION_END    if (!primask) __enable_irq();
123
+#define CRITICAL_SECTION_START  uint32_t primask = __get_PRIMASK(); __disable_irq()
124
+#define CRITICAL_SECTION_END    if (!primask) __enable_irq()
125
+#define ISRS_ENABLED() (!__get_PRIMASK())
126
+#define ENABLE_ISRS()  __enable_irq()
127
+#define DISABLE_ISRS() __disable_irq()
125 128
 
126 129
 //Utility functions
127 130
 int freeMemory(void);

+ 5
- 2
Marlin/src/HAL/HAL_STM32F1/HAL.h View File

@@ -119,8 +119,11 @@ void HAL_init();
119 119
   #define analogInputToDigitalPin(p) (p)
120 120
 #endif
121 121
 
122
-#define CRITICAL_SECTION_START  noInterrupts();
123
-#define CRITICAL_SECTION_END    interrupts();
122
+#define CRITICAL_SECTION_START  uint32_t primask = __get_PRIMASK(); __disable_irq()
123
+#define CRITICAL_SECTION_END    if (!primask) __enable_irq()
124
+#define ISRS_ENABLED() (!__get_PRIMASK())
125
+#define ENABLE_ISRS()  __enable_irq()
126
+#define DISABLE_ISRS() __disable_irq()
124 127
 
125 128
 // On AVR this is in math.h?
126 129
 #define square(x) ((x)*(x))

+ 5
- 2
Marlin/src/HAL/HAL_STM32F4/HAL.h View File

@@ -118,8 +118,11 @@
118 118
   #define analogInputToDigitalPin(p) (p)
119 119
 #endif
120 120
 
121
-#define CRITICAL_SECTION_START  noInterrupts();
122
-#define CRITICAL_SECTION_END    interrupts();
121
+#define CRITICAL_SECTION_START  uint32_t primask = __get_PRIMASK(); __disable_irq()
122
+#define CRITICAL_SECTION_END    if (!primask) __enable_irq()
123
+#define ISRS_ENABLED() (!__get_PRIMASK())
124
+#define ENABLE_ISRS()  __enable_irq()
125
+#define DISABLE_ISRS() __disable_irq()
123 126
 
124 127
 // On AVR this is in math.h?
125 128
 #define square(x) ((x)*(x))

+ 5
- 2
Marlin/src/HAL/HAL_STM32F7/HAL.h View File

@@ -111,8 +111,11 @@
111 111
   #define analogInputToDigitalPin(p) (p)
112 112
 #endif
113 113
 
114
-#define CRITICAL_SECTION_START  noInterrupts();
115
-#define CRITICAL_SECTION_END    interrupts();
114
+#define CRITICAL_SECTION_START  uint32_t primask = __get_PRIMASK(); __disable_irq()
115
+#define CRITICAL_SECTION_END    if (!primask) __enable_irq()
116
+#define ISRS_ENABLED() (!__get_PRIMASK())
117
+#define ENABLE_ISRS()  __enable_irq()
118
+#define DISABLE_ISRS() __disable_irq()
116 119
 
117 120
 // On AVR this is in math.h?
118 121
 #define square(x) ((x)*(x))

+ 5
- 2
Marlin/src/HAL/HAL_TEENSY35_36/HAL.h View File

@@ -88,8 +88,11 @@ typedef int8_t pin_t;
88 88
   #define analogInputToDigitalPin(p) ((p < 12u) ? (p) + 54u : -1)
89 89
 #endif
90 90
 
91
-#define CRITICAL_SECTION_START  unsigned char _sreg = SREG; cli();
92
-#define CRITICAL_SECTION_END    SREG = _sreg;
91
+#define CRITICAL_SECTION_START  uint32_t primask = __get_PRIMASK(); __disable_irq()
92
+#define CRITICAL_SECTION_END    if (!primask) __enable_irq()
93
+#define ISRS_ENABLED() (!__get_PRIMASK())
94
+#define ENABLE_ISRS()  __enable_irq()
95
+#define DISABLE_ISRS() __disable_irq()
93 96
 
94 97
 #undef sq
95 98
 #define sq(x) ((x)*(x))

+ 13
- 10
Marlin/src/module/endstops.cpp View File

@@ -578,19 +578,22 @@ void Endstops::update() {
578 578
 
579 579
   // Call the endstop triggered routine for single endstops
580 580
   #define PROCESS_ENDSTOP(AXIS,MINMAX) do { \
581
-      if (TEST_ENDSTOP(_ENDSTOP(AXIS, MINMAX))) { \
582
-        _ENDSTOP_HIT(AXIS, MINMAX); \
583
-        planner.endstop_triggered(_AXIS(AXIS)); \
584
-      } \
585
-    }while(0)
581
+    if (TEST_ENDSTOP(_ENDSTOP(AXIS, MINMAX))) { \
582
+      _ENDSTOP_HIT(AXIS, MINMAX); \
583
+      planner.endstop_triggered(_AXIS(AXIS)); \
584
+    } \
585
+  }while(0)
586 586
 
587
-  // Call the endstop triggered routine for single endstops
587
+  // Call the endstop triggered routine for dual endstops
588 588
   #define PROCESS_DUAL_ENDSTOP(AXIS1, AXIS2, MINMAX) do { \
589
-      if (TEST_ENDSTOP(_ENDSTOP(AXIS1, MINMAX)) || TEST_ENDSTOP(_ENDSTOP(AXIS2, MINMAX))) { \
590
-        _ENDSTOP_HIT(AXIS1, MINMAX); \
589
+    const byte dual_hit = TEST_ENDSTOP(_ENDSTOP(AXIS1, MINMAX)) | (TEST_ENDSTOP(_ENDSTOP(AXIS2, MINMAX)) << 1); \
590
+    if (dual_hit) { \
591
+      _ENDSTOP_HIT(AXIS1, MINMAX); \
592
+      /* if not performing home or if both endstops were trigged during homing... */ \
593
+      if (!stepper.performing_homing || dual_hit == 0x3) \
591 594
         planner.endstop_triggered(_AXIS(AXIS1)); \
592
-      } \
593
-    }while(0)
595
+    } \
596
+  }while(0)
594 597
 
595 598
   #if ENABLED(G38_PROBE_TARGET) && PIN_EXISTS(Z_MIN_PROBE) && !(CORE_IS_XY || CORE_IS_XZ)
596 599
     // If G38 command is active check Z_MIN_PROBE for ALL movement

+ 9
- 1
Marlin/src/module/endstops.h View File

@@ -108,7 +108,15 @@ class Endstops {
108 108
     /**
109 109
      * Get current endstops state
110 110
      */
111
-    FORCE_INLINE static esbits_t state() { return live_state; }
111
+    FORCE_INLINE static esbits_t state() {
112
+      return
113
+        #if ENABLED(ENDSTOP_NOISE_FILTER)
114
+          validated_live_state
115
+        #else
116
+          live_state
117
+        #endif
118
+      ;
119
+    }
112 120
 
113 121
     /**
114 122
      * Report endstop hits to serial. Called from loop().

+ 13
- 5
Marlin/src/module/planner.cpp View File

@@ -2467,9 +2467,13 @@ void Planner::_set_position_mm(const float &a, const float &b, const float &c, c
2467 2467
     position_float[C_AXIS] = c;
2468 2468
     position_float[E_AXIS] = e;
2469 2469
   #endif
2470
-  previous_nominal_speed_sqr = 0.0; // Resets planner junction speeds. Assumes start from rest.
2471
-  ZERO(previous_speed);
2472
-  buffer_sync_block();
2470
+  if (has_blocks_queued()) {
2471
+    //previous_nominal_speed_sqr = 0.0; // Reset planner junction speeds. Assume start from rest.
2472
+    //ZERO(previous_speed);
2473
+    buffer_sync_block();
2474
+  }
2475
+  else
2476
+    stepper.set_position(position[A_AXIS], position[B_AXIS], position[C_AXIS], position[E_AXIS]);
2473 2477
 }
2474 2478
 
2475 2479
 void Planner::set_position_mm_kinematic(const float (&cart)[XYZE]) {
@@ -2501,8 +2505,12 @@ void Planner::set_position_mm(const AxisEnum axis, const float &v) {
2501 2505
   #if HAS_POSITION_FLOAT
2502 2506
     position_float[axis] = v;
2503 2507
   #endif
2504
-  previous_speed[axis] = 0.0;
2505
-  buffer_sync_block();
2508
+  if (has_blocks_queued()) {
2509
+    //previous_speed[axis] = 0.0;
2510
+    buffer_sync_block();
2511
+  }
2512
+  else
2513
+    stepper.set_position(axis, position[axis]);
2506 2514
 }
2507 2515
 
2508 2516
 // Recalculate the steps/s^2 acceleration rates, based on the mm/s^2

+ 58
- 47
Marlin/src/module/stepper.cpp View File

@@ -102,13 +102,13 @@ uint8_t Stepper::last_direction_bits = 0,
102 102
 bool Stepper::abort_current_block;
103 103
 
104 104
 #if ENABLED(X_DUAL_ENDSTOPS)
105
-  bool Stepper::locked_x_motor = false, Stepper::locked_x2_motor = false;
105
+  bool Stepper::locked_X_motor = false, Stepper::locked_X2_motor = false;
106 106
 #endif
107 107
 #if ENABLED(Y_DUAL_ENDSTOPS)
108
-  bool Stepper::locked_y_motor = false, Stepper::locked_y2_motor = false;
108
+  bool Stepper::locked_Y_motor = false, Stepper::locked_Y2_motor = false;
109 109
 #endif
110 110
 #if ENABLED(Z_DUAL_ENDSTOPS)
111
-  bool Stepper::locked_z_motor = false, Stepper::locked_z2_motor = false;
111
+  bool Stepper::locked_Z_motor = false, Stepper::locked_Z2_motor = false;
112 112
 #endif
113 113
 
114 114
 /**
@@ -182,26 +182,20 @@ uint8_t Stepper::step_loops, Stepper::step_loops_nominal;
182 182
 volatile int32_t Stepper::endstops_trigsteps[XYZ];
183 183
 
184 184
 #if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
185
-  #define LOCKED_X_MOTOR  locked_x_motor
186
-  #define LOCKED_Y_MOTOR  locked_y_motor
187
-  #define LOCKED_Z_MOTOR  locked_z_motor
188
-  #define LOCKED_X2_MOTOR locked_x2_motor
189
-  #define LOCKED_Y2_MOTOR locked_y2_motor
190
-  #define LOCKED_Z2_MOTOR locked_z2_motor
191
-  #define DUAL_ENDSTOP_APPLY_STEP(A,V)                                                                                                      \
192
-    if (performing_homing) {                                                                                                                \
193
-      if (A##_HOME_DIR < 0) {                                                                                                               \
194
-        if (!(TEST(endstops.state(), A##_MIN) && count_direction[_AXIS(A)] < 0) && !LOCKED_##A##_MOTOR) A##_STEP_WRITE(V);     \
195
-        if (!(TEST(endstops.state(), A##2_MIN) && count_direction[_AXIS(A)] < 0) && !LOCKED_##A##2_MOTOR) A##2_STEP_WRITE(V);  \
196
-      }                                                                                                                                     \
197
-      else {                                                                                                                                \
198
-        if (!(TEST(endstops.state(), A##_MAX) && count_direction[_AXIS(A)] > 0) && !LOCKED_##A##_MOTOR) A##_STEP_WRITE(V);     \
199
-        if (!(TEST(endstops.state(), A##2_MAX) && count_direction[_AXIS(A)] > 0) && !LOCKED_##A##2_MOTOR) A##2_STEP_WRITE(V);  \
200
-      }                                                                                                                                     \
201
-    }                                                                                                                                       \
202
-    else {                                                                                                                                  \
203
-      A##_STEP_WRITE(V);                                                                                                                    \
204
-      A##2_STEP_WRITE(V);                                                                                                                   \
185
+  #define DUAL_ENDSTOP_APPLY_STEP(A,V)                                                                                        \
186
+    if (performing_homing) {                                                                                                  \
187
+      if (A##_HOME_DIR < 0) {                                                                                                 \
188
+        if (!(TEST(endstops.state(), A##_MIN) && count_direction[_AXIS(A)] < 0) && !locked_##A##_motor) A##_STEP_WRITE(V);    \
189
+        if (!(TEST(endstops.state(), A##2_MIN) && count_direction[_AXIS(A)] < 0) && !locked_##A##2_motor) A##2_STEP_WRITE(V); \
190
+      }                                                                                                                       \
191
+      else {                                                                                                                  \
192
+        if (!(TEST(endstops.state(), A##_MAX) && count_direction[_AXIS(A)] > 0) && !locked_##A##_motor) A##_STEP_WRITE(V);    \
193
+        if (!(TEST(endstops.state(), A##2_MAX) && count_direction[_AXIS(A)] > 0) && !locked_##A##2_motor) A##2_STEP_WRITE(V); \
194
+      }                                                                                                                       \
195
+    }                                                                                                                         \
196
+    else {                                                                                                                    \
197
+      A##_STEP_WRITE(V);                                                                                                      \
198
+      A##2_STEP_WRITE(V);                                                                                                     \
205 199
     }
206 200
 #endif
207 201
 
@@ -1150,19 +1144,8 @@ void Stepper::set_directions() {
1150 1144
 HAL_STEP_TIMER_ISR {
1151 1145
   HAL_timer_isr_prologue(STEP_TIMER_NUM);
1152 1146
 
1153
-  // Program timer compare for the maximum period, so it does NOT
1154
-  // flag an interrupt while this ISR is running - So changes from small
1155
-  // periods to big periods are respected and the timer does not reset to 0
1156
-  HAL_timer_set_compare(STEP_TIMER_NUM, HAL_TIMER_TYPE_MAX);
1157
-
1158
-  // Call the ISR scheduler
1159
-  hal_timer_t ticks = Stepper::isr_scheduler();
1160
-
1161
-  // Now 'ticks' contains the period to the next Stepper ISR - And we are
1162
-  // sure that the time has not arrived yet - Warrantied by the scheduler
1163
-
1164
-  // Set the next ISR to fire at the proper time
1165
-  HAL_timer_set_compare(STEP_TIMER_NUM, ticks);
1147
+  // Call the ISR
1148
+  Stepper::isr();
1166 1149
 
1167 1150
   HAL_timer_isr_epilogue(STEP_TIMER_NUM);
1168 1151
 }
@@ -1173,8 +1156,15 @@ HAL_STEP_TIMER_ISR {
1173 1156
   #define STEP_MULTIPLY(A,B) MultiU24X32toH16(A, B)
1174 1157
 #endif
1175 1158
 
1176
-hal_timer_t Stepper::isr_scheduler() {
1177
-  uint32_t interval;
1159
+void Stepper::isr() {
1160
+
1161
+  // Disable interrupts, to avoid ISR preemption while we reprogram the period
1162
+  DISABLE_ISRS();
1163
+
1164
+  // Program timer compare for the maximum period, so it does NOT
1165
+  // flag an interrupt while this ISR is running - So changes from small
1166
+  // periods to big periods are respected and the timer does not reset to 0
1167
+  HAL_timer_set_compare(STEP_TIMER_NUM, HAL_TIMER_TYPE_MAX);
1178 1168
 
1179 1169
   // Count of ticks for the next ISR
1180 1170
   hal_timer_t next_isr_ticks = 0;
@@ -1185,6 +1175,9 @@ hal_timer_t Stepper::isr_scheduler() {
1185 1175
   // We need this variable here to be able to use it in the following loop
1186 1176
   hal_timer_t min_ticks;
1187 1177
   do {
1178
+    // Enable ISRs so the USART processing latency is reduced
1179
+    ENABLE_ISRS();
1180
+
1188 1181
     // Run main stepping pulse phase ISR if we have to
1189 1182
     if (!nextMainISR) Stepper::stepper_pulse_phase_isr();
1190 1183
 
@@ -1198,13 +1191,15 @@ hal_timer_t Stepper::isr_scheduler() {
1198 1191
     // Run main stepping block processing ISR if we have to
1199 1192
     if (!nextMainISR) nextMainISR = Stepper::stepper_block_phase_isr();
1200 1193
 
1201
-    #if ENABLED(LIN_ADVANCE)
1202
-      // Select the closest interval in time
1203
-      interval = (nextAdvanceISR <= nextMainISR) ? nextAdvanceISR : nextMainISR;
1204
-    #else
1205
-      // The interval is just the remaining time to the stepper ISR
1206
-      interval = nextMainISR;
1207
-    #endif
1194
+    uint32_t interval =
1195
+      #if ENABLED(LIN_ADVANCE)
1196
+        // Select the closest interval in time
1197
+        MIN(nextAdvanceISR, nextMainISR)
1198
+      #else
1199
+        // The interval is just the remaining time to the stepper ISR
1200
+        nextMainISR
1201
+      #endif
1202
+    ;
1208 1203
 
1209 1204
     // Limit the value to the maximum possible value of the timer
1210 1205
     NOMORE(interval, HAL_TIMER_TYPE_MAX);
@@ -1244,6 +1239,16 @@ hal_timer_t Stepper::isr_scheduler() {
1244 1239
     next_isr_ticks += interval;
1245 1240
 
1246 1241
     /**
1242
+     *  The following section must be done with global interrupts disabled.
1243
+     * We want nothing to interrupt it, as that could mess the calculations
1244
+     * we do for the next value to program in the period register of the
1245
+     * stepper timer and lead to skipped ISRs (if the value we happen to program
1246
+     * is less than the current count due to something preempting between the
1247
+     * read and the write of the new period value).
1248
+     */
1249
+    DISABLE_ISRS();
1250
+
1251
+    /**
1247 1252
      * Get the current tick value + margin
1248 1253
      * Assuming at least 6µs between calls to this ISR...
1249 1254
      * On AVR the ISR epilogue is estimated at 40 instructions - close to 2.5µS.
@@ -1264,8 +1269,14 @@ hal_timer_t Stepper::isr_scheduler() {
1264 1269
     // Advance pulses if not enough time to wait for the next ISR
1265 1270
   } while (next_isr_ticks < min_ticks);
1266 1271
 
1267
-  // Return the count of ticks for the next ISR
1268
-  return (hal_timer_t)next_isr_ticks;
1272
+  // Now 'next_isr_ticks' contains the period to the next Stepper ISR - And we are
1273
+  // sure that the time has not arrived yet - Warrantied by the scheduler
1274
+
1275
+  // Set the next ISR to fire at the proper time
1276
+  HAL_timer_set_compare(STEP_TIMER_NUM, hal_timer_t(next_isr_ticks));
1277
+
1278
+  // Don't forget to finally reenable interrupts
1279
+  ENABLE_ISRS();
1269 1280
 }
1270 1281
 
1271 1282
 /**

+ 32
- 14
Marlin/src/module/stepper.h View File

@@ -81,13 +81,13 @@ class Stepper {
81 81
     static bool abort_current_block;        // Signals to the stepper that current block should be aborted
82 82
 
83 83
     #if ENABLED(X_DUAL_ENDSTOPS)
84
-      static bool locked_x_motor, locked_x2_motor;
84
+      static bool locked_X_motor, locked_X2_motor;
85 85
     #endif
86 86
     #if ENABLED(Y_DUAL_ENDSTOPS)
87
-      static bool locked_y_motor, locked_y2_motor;
87
+      static bool locked_Y_motor, locked_Y2_motor;
88 88
     #endif
89 89
     #if ENABLED(Z_DUAL_ENDSTOPS)
90
-      static bool locked_z_motor, locked_z2_motor;
90
+      static bool locked_Z_motor, locked_Z2_motor;
91 91
     #endif
92 92
 
93 93
     // Counter variables for the Bresenham line tracer
@@ -168,7 +168,7 @@ class Stepper {
168 168
     // Interrupt Service Routines
169 169
 
170 170
     // The ISR scheduler
171
-    static hal_timer_t isr_scheduler();
171
+    static void isr();
172 172
 
173 173
     // The stepper pulse phase ISR
174 174
     static void stepper_pulse_phase_isr();
@@ -222,18 +222,18 @@ class Stepper {
222 222
 
223 223
     #if ENABLED(X_DUAL_ENDSTOPS)
224 224
       FORCE_INLINE static void set_homing_flag_x(const bool state) { performing_homing = state; }
225
-      FORCE_INLINE static void set_x_lock(const bool state) { locked_x_motor = state; }
226
-      FORCE_INLINE static void set_x2_lock(const bool state) { locked_x2_motor = state; }
225
+      FORCE_INLINE static void set_x_lock(const bool state) { locked_X_motor = state; }
226
+      FORCE_INLINE static void set_x2_lock(const bool state) { locked_X2_motor = state; }
227 227
     #endif
228 228
     #if ENABLED(Y_DUAL_ENDSTOPS)
229 229
       FORCE_INLINE static void set_homing_flag_y(const bool state) { performing_homing = state; }
230
-      FORCE_INLINE static void set_y_lock(const bool state) { locked_y_motor = state; }
231
-      FORCE_INLINE static void set_y2_lock(const bool state) { locked_y2_motor = state; }
230
+      FORCE_INLINE static void set_y_lock(const bool state) { locked_Y_motor = state; }
231
+      FORCE_INLINE static void set_y2_lock(const bool state) { locked_Y2_motor = state; }
232 232
     #endif
233 233
     #if ENABLED(Z_DUAL_ENDSTOPS)
234 234
       FORCE_INLINE static void set_homing_flag_z(const bool state) { performing_homing = state; }
235
-      FORCE_INLINE static void set_z_lock(const bool state) { locked_z_motor = state; }
236
-      FORCE_INLINE static void set_z2_lock(const bool state) { locked_z2_motor = state; }
235
+      FORCE_INLINE static void set_z_lock(const bool state) { locked_Z_motor = state; }
236
+      FORCE_INLINE static void set_z2_lock(const bool state) { locked_Z2_motor = state; }
237 237
     #endif
238 238
 
239 239
     #if ENABLED(BABYSTEPPING)
@@ -247,16 +247,34 @@ class Stepper {
247 247
     // Set the current position in steps
248 248
     inline static void set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e) {
249 249
       planner.synchronize();
250
-      CRITICAL_SECTION_START;
250
+
251
+      // Disable stepper interrupts, to ensure atomic setting of all the position variables
252
+      const bool was_enabled = STEPPER_ISR_ENABLED();
253
+      if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
254
+
255
+      // Set position
251 256
       _set_position(a, b, c, e);
252
-      CRITICAL_SECTION_END;
257
+
258
+      // Reenable Stepper ISR
259
+      if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
253 260
     }
254 261
 
255 262
     inline static void set_position(const AxisEnum a, const int32_t &v) {
256 263
       planner.synchronize();
257
-      CRITICAL_SECTION_START;
264
+
265
+    #ifdef __AVR__
266
+      // Protect the access to the position. Only required for AVR, as
267
+      //  any 32bit CPU offers atomic access to 32bit variables
268
+      const bool was_enabled = STEPPER_ISR_ENABLED();
269
+      if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
270
+    #endif
271
+
258 272
       count_position[a] = v;
259
-      CRITICAL_SECTION_END;
273
+
274
+    #ifdef __AVR__
275
+      // Reenable Stepper ISR
276
+      if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
277
+    #endif
260 278
     }
261 279
 
262 280
   private:

Loading…
Cancel
Save