Browse Source

Refactor and optimize Stepper/Planner

Better encapsulation and considerably reduce stepper jitter
etagle 7 years ago
parent
commit
a11eb50a3e

+ 1
- 1
Marlin/src/Marlin.cpp View File

269
 }
269
 }
270
 
270
 
271
 void quickstop_stepper() {
271
 void quickstop_stepper() {
272
-  stepper.quick_stop();
272
+  planner.quick_stop();
273
   planner.synchronize();
273
   planner.synchronize();
274
   set_current_from_steppers_for_axis(ALL_AXES);
274
   set_current_from_steppers_for_axis(ALL_AXES);
275
   SYNC_PLAN_POSITION_KINEMATIC();
275
   SYNC_PLAN_POSITION_KINEMATIC();

+ 6
- 3
Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp View File

262
             z_position = end[Z_AXIS];
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
         } //else printf("FIRST MOVE PRUNED  ");
267
         } //else printf("FIRST MOVE PRUNED  ");
267
       }
268
       }
268
 
269
 
319
           e_position = end[E_AXIS];
320
           e_position = end[E_AXIS];
320
           z_position = end[Z_AXIS];
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
         current_yi += dyi;
325
         current_yi += dyi;
324
         yi_cnt--;
326
         yi_cnt--;
325
       }
327
       }
342
           z_position = end[Z_AXIS];
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
         current_xi += dxi;
349
         current_xi += dxi;
347
         xi_cnt--;
350
         xi_cnt--;
348
       }
351
       }

+ 1
- 1
Marlin/src/gcode/config/M540.cpp View File

33
 void GcodeSuite::M540() {
33
 void GcodeSuite::M540() {
34
 
34
 
35
   if (parser.seen('S'))
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 View File

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

+ 1
- 1
Marlin/src/gcode/control/M80_M81.cpp View File

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

+ 6
- 3
Marlin/src/gcode/motion/G2_G3.cpp View File

197
       // i.e., Complete the angular vector in the given time.
197
       // i.e., Complete the angular vector in the given time.
198
       inverse_kinematics(raw);
198
       inverse_kinematics(raw);
199
       ADJUST_DELTA(raw);
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
       oldA = delta[A_AXIS]; oldB = delta[B_AXIS];
202
       oldA = delta[A_AXIS]; oldB = delta[B_AXIS];
202
     #elif HAS_UBL_AND_CURVES
203
     #elif HAS_UBL_AND_CURVES
203
       float pos[XYZ] = { raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS] };
204
       float pos[XYZ] = { raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS] };
204
       planner.apply_leveling(pos);
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
     #else
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
     #endif
211
     #endif
209
   }
212
   }
210
 
213
 

+ 2
- 4
Marlin/src/lcd/ultralcd.cpp View File

2421
 
2421
 
2422
     void _lcd_do_nothing() {}
2422
     void _lcd_do_nothing() {}
2423
     void _lcd_hard_stop() {
2423
     void _lcd_hard_stop() {
2424
-      stepper.quick_stop();
2425
       const screenFunc_t old_screen = currentScreen;
2424
       const screenFunc_t old_screen = currentScreen;
2426
       currentScreen = _lcd_do_nothing;
2425
       currentScreen = _lcd_do_nothing;
2427
-      while (planner.movesplanned()) idle();
2426
+      planner.quick_stop();
2428
       currentScreen = old_screen;
2427
       currentScreen = old_screen;
2429
-      stepper.cleaning_buffer_counter = 0;
2430
       set_current_from_steppers_for_axis(ALL_AXES);
2428
       set_current_from_steppers_for_axis(ALL_AXES);
2431
       sync_plan_position();
2429
       sync_plan_position();
2432
     }
2430
     }
3856
 
3854
 
3857
     // M540 S - Abort on endstop hit when SD printing
3855
     // M540 S - Abort on endstop hit when SD printing
3858
     #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
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
     #endif
3858
     #endif
3861
 
3859
 
3862
     END_MENU();
3860
     END_MENU();

+ 6
- 6
Marlin/src/module/endstops.cpp View File

208
     #endif
208
     #endif
209
 
209
 
210
     #define _ENDSTOP_HIT_ECHO(A,C) do{ \
210
     #define _ENDSTOP_HIT_ECHO(A,C) do{ \
211
-      SERIAL_ECHOPAIR(" " STRINGIFY(A) ":", stepper.triggered_position_mm(_AXIS(A))); \
211
+      SERIAL_ECHOPAIR(" " STRINGIFY(A) ":", planner.triggered_position_mm(_AXIS(A))); \
212
       _SET_STOP_CHAR(A,C); }while(0)
212
       _SET_STOP_CHAR(A,C); }while(0)
213
 
213
 
214
     #define _ENDSTOP_HIT_TEST(A,C) \
214
     #define _ENDSTOP_HIT_TEST(A,C) \
238
     hit_on_purpose();
238
     hit_on_purpose();
239
 
239
 
240
     #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) && ENABLED(SDSUPPORT)
240
     #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) && ENABLED(SDSUPPORT)
241
-      if (stepper.abort_on_endstop_hit) {
241
+      if (planner.abort_on_endstop_hit) {
242
         card.sdprinting = false;
242
         card.sdprinting = false;
243
         card.closefile();
243
         card.closefile();
244
         quickstop_stepper();
244
         quickstop_stepper();
349
       UPDATE_ENDSTOP_BIT(AXIS, MINMAX); \
349
       UPDATE_ENDSTOP_BIT(AXIS, MINMAX); \
350
       if (TEST_ENDSTOP(_ENDSTOP(AXIS, MINMAX))) { \
350
       if (TEST_ENDSTOP(_ENDSTOP(AXIS, MINMAX))) { \
351
         _ENDSTOP_HIT(AXIS, MINMAX); \
351
         _ENDSTOP_HIT(AXIS, MINMAX); \
352
-        stepper.endstop_triggered(_AXIS(AXIS)); \
352
+        planner.endstop_triggered(_AXIS(AXIS)); \
353
       } \
353
       } \
354
     }while(0)
354
     }while(0)
355
 
355
 
358
     if (G38_move) {
358
     if (G38_move) {
359
       UPDATE_ENDSTOP_BIT(Z, MIN_PROBE);
359
       UPDATE_ENDSTOP_BIT(Z, MIN_PROBE);
360
       if (TEST_ENDSTOP(_ENDSTOP(Z, MIN_PROBE))) {
360
       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)); }
361
+        if      (stepper.current_block->steps[_AXIS(X)] > 0) { _ENDSTOP_HIT(X, MIN); planner.endstop_triggered(_AXIS(X)); }
362
+        else if (stepper.current_block->steps[_AXIS(Y)] > 0) { _ENDSTOP_HIT(Y, MIN); planner.endstop_triggered(_AXIS(Y)); }
363
+        else if (stepper.current_block->steps[_AXIS(Z)] > 0) { _ENDSTOP_HIT(Z, MIN); planner.endstop_triggered(_AXIS(Z)); }
364
         G38_endstop_hit = true;
364
         G38_endstop_hit = true;
365
       }
365
       }
366
     }
366
     }

+ 12
- 9
Marlin/src/module/motion.cpp View File

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

+ 388
- 200
Marlin/src/module/planner.cpp View File

100
  * A ring buffer of moves described in steps
100
  * A ring buffer of moves described in steps
101
  */
101
  */
102
 block_t Planner::block_buffer[BLOCK_BUFFER_SIZE];
102
 block_t Planner::block_buffer[BLOCK_BUFFER_SIZE];
103
-volatile uint8_t Planner::block_buffer_head, // Index of the next block to be pushed
104
-                 Planner::block_buffer_tail;
103
+volatile uint8_t Planner::block_buffer_head,  // Index of the next block to be pushed
104
+                 Planner::block_buffer_tail;  // Index of the busy block, if any
105
+uint16_t Planner::cleaning_buffer_counter;   // A counter to disable queuing of blocks
105
 
106
 
106
-float Planner::max_feedrate_mm_s[XYZE_N], // Max speeds in mm per second
107
+float Planner::max_feedrate_mm_s[XYZE_N],   // Max speeds in mm per second
107
       Planner::axis_steps_per_mm[XYZE_N],
108
       Planner::axis_steps_per_mm[XYZE_N],
108
       Planner::steps_to_mm[XYZE_N];
109
       Planner::steps_to_mm[XYZE_N];
109
 
110
 
111
+#if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
112
+  bool Planner::abort_on_endstop_hit = false;
113
+#endif
114
+
110
 #if ENABLED(DISTINCT_E_FACTORS)
115
 #if ENABLED(DISTINCT_E_FACTORS)
111
   uint8_t Planner::last_extruder = 0;     // Respond to extruder change
116
   uint8_t Planner::last_extruder = 0;     // Respond to extruder change
112
 #endif
117
 #endif
175
 uint32_t Planner::cutoff_long;
180
 uint32_t Planner::cutoff_long;
176
 
181
 
177
 float Planner::previous_speed[NUM_AXIS],
182
 float Planner::previous_speed[NUM_AXIS],
178
-      Planner::previous_nominal_speed;
183
+      Planner::previous_nominal_speed_sqr;
179
 
184
 
180
 #if ENABLED(DISABLE_INACTIVE_EXTRUDER)
185
 #if ENABLED(DISABLE_INACTIVE_EXTRUDER)
181
   uint8_t Planner::g_uc_extruder_last_move[EXTRUDERS] = { 0 };
186
   uint8_t Planner::g_uc_extruder_last_move[EXTRUDERS] = { 0 };
212
     ZERO(position_float);
217
     ZERO(position_float);
213
   #endif
218
   #endif
214
   ZERO(previous_speed);
219
   ZERO(previous_speed);
215
-  previous_nominal_speed = 0.0;
220
+  previous_nominal_speed_sqr = 0.0;
216
   #if ABL_PLANAR
221
   #if ABL_PLANAR
217
     bed_level_matrix.set_to_identity();
222
     bed_level_matrix.set_to_identity();
218
   #endif
223
   #endif
363
     //
368
     //
364
     static uint32_t get_period_inverse(uint32_t d) {
369
     static uint32_t get_period_inverse(uint32_t d) {
365
 
370
 
366
-       static const uint8_t inv_tab[256] PROGMEM = {
371
+      static const uint8_t inv_tab[256] PROGMEM = {
367
         255,253,252,250,248,246,244,242,240,238,236,234,233,231,229,227,
372
         255,253,252,250,248,246,244,242,240,238,236,234,233,231,229,227,
368
         225,224,222,220,218,217,215,213,212,210,208,207,205,203,202,200,
373
         225,224,222,220,218,217,215,213,212,210,208,207,205,203,202,200,
369
         199,197,195,194,192,191,189,188,186,185,183,182,180,179,178,176,
374
         199,197,195,194,192,191,189,188,186,185,183,182,180,179,178,176,
727
     }
732
     }
728
   #else
733
   #else
729
     // All the other 32 CPUs can easily perform the inverse using hardware division,
734
     // All the other 32 CPUs can easily perform the inverse using hardware division,
730
-    // so we don´t need to reduce precision or to use assembly language at all.
731
-
735
+    // so we don't need to reduce precision or to use assembly language at all.
732
     // This routine, for all the other archs, returns 0x100000000 / d ~= 0xFFFFFFFF / d
736
     // This routine, for all the other archs, returns 0x100000000 / d ~= 0xFFFFFFFF / d
733
-    static FORCE_INLINE uint32_t get_period_inverse(uint32_t d) {
734
-      return 0xFFFFFFFF / d;
735
-    }
737
+    static FORCE_INLINE uint32_t get_period_inverse(const uint32_t d) { return 0xFFFFFFFF / d; }
736
   #endif
738
   #endif
737
 #endif
739
 #endif
738
 
740
 
743
  * by the provided factors.
745
  * by the provided factors.
744
  */
746
  */
745
 void Planner::calculate_trapezoid_for_block(block_t* const block, const float &entry_factor, const float &exit_factor) {
747
 void Planner::calculate_trapezoid_for_block(block_t* const block, const float &entry_factor, const float &exit_factor) {
748
+
746
   uint32_t initial_rate = CEIL(block->nominal_rate * entry_factor),
749
   uint32_t initial_rate = CEIL(block->nominal_rate * entry_factor),
747
            final_rate = CEIL(block->nominal_rate * exit_factor); // (steps per second)
750
            final_rate = CEIL(block->nominal_rate * exit_factor); // (steps per second)
748
 
751
 
757
   const int32_t accel = block->acceleration_steps_per_s2;
760
   const int32_t accel = block->acceleration_steps_per_s2;
758
 
761
 
759
           // Steps required for acceleration, deceleration to/from nominal rate
762
           // Steps required for acceleration, deceleration to/from nominal rate
760
-  int32_t accelerate_steps = CEIL(estimate_acceleration_distance(initial_rate, block->nominal_rate, accel)),
761
-          decelerate_steps = FLOOR(estimate_acceleration_distance(block->nominal_rate, final_rate, -accel)),
763
+  uint32_t accelerate_steps = CEIL(estimate_acceleration_distance(initial_rate, block->nominal_rate, accel)),
764
+           decelerate_steps = FLOOR(estimate_acceleration_distance(block->nominal_rate, final_rate, -accel));
762
           // Steps between acceleration and deceleration, if any
765
           // Steps between acceleration and deceleration, if any
763
-          plateau_steps = block->step_event_count - accelerate_steps - decelerate_steps;
766
+  int32_t plateau_steps = block->step_event_count - accelerate_steps - decelerate_steps;
764
 
767
 
765
   // Does accelerate_steps + decelerate_steps exceed step_event_count?
768
   // Does accelerate_steps + decelerate_steps exceed step_event_count?
766
   // Then we can't possibly reach the nominal rate, there will be no cruising.
769
   // Then we can't possibly reach the nominal rate, there will be no cruising.
767
   // Use intersection_distance() to calculate accel / braking time in order to
770
   // Use intersection_distance() to calculate accel / braking time in order to
768
   // reach the final_rate exactly at the end of this block.
771
   // reach the final_rate exactly at the end of this block.
769
   if (plateau_steps < 0) {
772
   if (plateau_steps < 0) {
770
-    accelerate_steps = CEIL(intersection_distance(initial_rate, final_rate, accel, block->step_event_count));
771
-    NOLESS(accelerate_steps, 0); // Check limits due to numerical round-off
772
-    accelerate_steps = min((uint32_t)accelerate_steps, block->step_event_count);//(We can cast here to unsigned, because the above line ensures that we are above zero)
773
+    const float accelerate_steps_float = CEIL(intersection_distance(initial_rate, final_rate, accel, block->step_event_count));
774
+    accelerate_steps = MIN(uint32_t(MAX(accelerate_steps_float, 0)), block->step_event_count);
773
     plateau_steps = 0;
775
     plateau_steps = 0;
774
 
776
 
775
     #if ENABLED(BEZIER_JERK_CONTROL)
777
     #if ENABLED(BEZIER_JERK_CONTROL)
796
 
798
 
797
   #endif
799
   #endif
798
 
800
 
799
-  CRITICAL_SECTION_START;  // Fill variables used by the stepper in a critical section
801
+  // Fill variables used by the stepper in a critical section
802
+  const bool was_enabled = STEPPER_ISR_ENABLED();
803
+  if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
804
+
800
   if (!TEST(block->flag, BLOCK_BIT_BUSY)) { // Don't update variables if block is busy.
805
   if (!TEST(block->flag, BLOCK_BIT_BUSY)) { // Don't update variables if block is busy.
801
     block->accelerate_until = accelerate_steps;
806
     block->accelerate_until = accelerate_steps;
802
     block->decelerate_after = accelerate_steps + plateau_steps;
807
     block->decelerate_after = accelerate_steps + plateau_steps;
810
     #endif
815
     #endif
811
     block->final_rate = final_rate;
816
     block->final_rate = final_rate;
812
   }
817
   }
813
-  CRITICAL_SECTION_END;
818
+  if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
814
 }
819
 }
815
 
820
 
816
-// "Junction jerk" in this context is the immediate change in speed at the junction of two blocks.
817
-// This method will calculate the junction jerk as the euclidean distance between the nominal
818
-// velocities of the respective blocks.
819
-//inline float junction_jerk(block_t *before, block_t *after) {
820
-//  return SQRT(
821
-//    POW((before->speed_x-after->speed_x), 2)+POW((before->speed_y-after->speed_y), 2));
822
-//}
823
-
824
 // The kernel called by recalculate() when scanning the plan from last to first entry.
821
 // The kernel called by recalculate() when scanning the plan from last to first entry.
825
-void Planner::reverse_pass_kernel(block_t* const current, const block_t* const next) {
826
-  if (current && next) {
827
-    // If entry speed is already at the maximum entry speed, no need to recheck. Block is cruising.
828
-    // If not, block in state of acceleration or deceleration. Reset entry speed to maximum and
829
-    // check for maximum allowable speed reductions to ensure maximum possible planned speed.
830
-    const float max_entry_speed = current->max_entry_speed;
831
-    if (current->entry_speed != max_entry_speed || TEST(next->flag, BLOCK_BIT_RECALCULATE)) {
832
-      // If nominal length true, max junction speed is guaranteed to be reached. Only compute
833
-      // for max allowable speed if block is decelerating and nominal length is false.
834
-      const float new_entry_speed = (TEST(current->flag, BLOCK_BIT_NOMINAL_LENGTH) || max_entry_speed <= next->entry_speed)
835
-        ? max_entry_speed
836
-        : MIN(max_entry_speed, max_allowable_speed(-current->acceleration, next->entry_speed, current->millimeters));
837
-      if (new_entry_speed != current->entry_speed) {
838
-        current->entry_speed = new_entry_speed;
822
+void Planner::reverse_pass_kernel(block_t* const current, const block_t * const next) {
823
+  if (current) {
824
+    // If entry speed is already at the maximum entry speed, and there was no change of speed
825
+    // in the next block, there is no need to recheck. Block is cruising and there is no need to
826
+    // compute anything for this block,
827
+    // If not, block entry speed needs to be recalculated to ensure maximum possible planned speed.
828
+    const float max_entry_speed_sqr = current->max_entry_speed_sqr;
829
+
830
+    // Compute maximum entry speed decelerating over the current block from its exit speed.
831
+    // If not at the maximum entry speed, or the previous block entry speed changed
832
+    if (current->entry_speed_sqr != max_entry_speed_sqr || (next && TEST(next->flag, BLOCK_BIT_RECALCULATE))) {
833
+
834
+      // If nominal length true, max junction speed is guaranteed to be reached.
835
+      // If a block can de/ac-celerate from nominal speed to zero within the length of the block, then
836
+      // the current block and next block junction speeds are guaranteed to always be at their maximum
837
+      // junction speeds in deceleration and acceleration, respectively. This is due to how the current
838
+      // block nominal speed limits both the current and next maximum junction speeds. Hence, in both
839
+      // the reverse and forward planners, the corresponding block junction speed will always be at the
840
+      // the maximum junction speed and may always be ignored for any speed reduction checks.
841
+
842
+      const float new_entry_speed_sqr = TEST(current->flag, BLOCK_BIT_NOMINAL_LENGTH)
843
+        ? max_entry_speed_sqr
844
+        : MIN(max_entry_speed_sqr, max_allowable_speed_sqr(-current->acceleration, next ? next->entry_speed_sqr : sq(MINIMUM_PLANNER_SPEED), current->millimeters));
845
+      if (current->entry_speed_sqr != new_entry_speed_sqr) {
846
+        current->entry_speed_sqr = new_entry_speed_sqr;
839
         SBI(current->flag, BLOCK_BIT_RECALCULATE);
847
         SBI(current->flag, BLOCK_BIT_RECALCULATE);
840
       }
848
       }
841
     }
849
     }
850
   if (movesplanned() > 2) {
858
   if (movesplanned() > 2) {
851
     const uint8_t endnr = next_block_index(block_buffer_tail); // tail is running. tail+1 shouldn't be altered because it's connected to the running block.
859
     const uint8_t endnr = next_block_index(block_buffer_tail); // tail is running. tail+1 shouldn't be altered because it's connected to the running block.
852
     uint8_t blocknr = prev_block_index(block_buffer_head);
860
     uint8_t blocknr = prev_block_index(block_buffer_head);
853
-    block_t* current = &block_buffer[blocknr];
854
-
855
-    // Last/newest block in buffer:
856
-    const float max_entry_speed = current->max_entry_speed;
857
-    if (current->entry_speed != max_entry_speed) {
858
-      // If nominal length true, max junction speed is guaranteed to be reached. Only compute
859
-      // for max allowable speed if block is decelerating and nominal length is false.
860
-      const float new_entry_speed = TEST(current->flag, BLOCK_BIT_NOMINAL_LENGTH)
861
-        ? max_entry_speed
862
-        : MIN(max_entry_speed, max_allowable_speed(-current->acceleration, MINIMUM_PLANNER_SPEED, current->millimeters));
863
-      if (current->entry_speed != new_entry_speed) {
864
-        current->entry_speed = new_entry_speed;
865
-        SBI(current->flag, BLOCK_BIT_RECALCULATE);
866
-      }
867
-    }
868
 
861
 
869
-    do {
870
-      const block_t * const next = current;
871
-      blocknr = prev_block_index(blocknr);
862
+    // Perform the reverse pass
863
+    block_t *current, *next = NULL;
864
+    while (blocknr != endnr) {
865
+      // Perform the reverse pass - Only consider non sync blocks
872
       current = &block_buffer[blocknr];
866
       current = &block_buffer[blocknr];
873
-      reverse_pass_kernel(current, next);
874
-    } while (blocknr != endnr);
867
+      if (!TEST(current->flag, BLOCK_BIT_SYNC_POSITION)) {
868
+        reverse_pass_kernel(current, next);
869
+        next = current;
870
+      }
871
+      // Advance to the next
872
+      blocknr = prev_block_index(blocknr);
873
+    }
875
   }
874
   }
876
 }
875
 }
877
 
876
 
878
 // The kernel called by recalculate() when scanning the plan from first to last entry.
877
 // The kernel called by recalculate() when scanning the plan from first to last entry.
879
-void Planner::forward_pass_kernel(const block_t* const previous, block_t* const current) {
878
+void Planner::forward_pass_kernel(const block_t * const previous, block_t* const current) {
880
   if (previous) {
879
   if (previous) {
881
     // If the previous block is an acceleration block, too short to complete the full speed
880
     // If the previous block is an acceleration block, too short to complete the full speed
882
     // change, adjust the entry speed accordingly. Entry speeds have already been reset,
881
     // change, adjust the entry speed accordingly. Entry speeds have already been reset,
883
     // maximized, and reverse-planned. If nominal length is set, max junction speed is
882
     // maximized, and reverse-planned. If nominal length is set, max junction speed is
884
     // guaranteed to be reached. No need to recheck.
883
     // guaranteed to be reached. No need to recheck.
885
     if (!TEST(previous->flag, BLOCK_BIT_NOMINAL_LENGTH)) {
884
     if (!TEST(previous->flag, BLOCK_BIT_NOMINAL_LENGTH)) {
886
-      if (previous->entry_speed < current->entry_speed) {
887
-        const float new_entry_speed = MIN(current->entry_speed, max_allowable_speed(-previous->acceleration, previous->entry_speed, previous->millimeters));
888
-        // Check for junction speed change
889
-        if (current->entry_speed != new_entry_speed) {
890
-          current->entry_speed = new_entry_speed;
885
+      if (previous->entry_speed_sqr < current->entry_speed_sqr) {
886
+        // Compute the maximum allowable speed
887
+        const float new_entry_speed_sqr = max_allowable_speed_sqr(-previous->acceleration, previous->entry_speed_sqr, previous->millimeters);
888
+        // If true, current block is full-acceleration
889
+        if (current->entry_speed_sqr > new_entry_speed_sqr) {
890
+          // Always <= max_entry_speed_sqr. Backward pass sets this.
891
+          current->entry_speed_sqr = new_entry_speed_sqr;
891
           SBI(current->flag, BLOCK_BIT_RECALCULATE);
892
           SBI(current->flag, BLOCK_BIT_RECALCULATE);
892
         }
893
         }
893
       }
894
       }
900
  * Once in reverse and once forward. This implements the forward pass.
901
  * Once in reverse and once forward. This implements the forward pass.
901
  */
902
  */
902
 void Planner::forward_pass() {
903
 void Planner::forward_pass() {
903
-  block_t* block[3] = { NULL, NULL, NULL };
904
-
905
-  for (uint8_t b = block_buffer_tail; b != block_buffer_head; b = next_block_index(b)) {
906
-    block[0] = block[1];
907
-    block[1] = block[2];
908
-    block[2] = &block_buffer[b];
909
-    forward_pass_kernel(block[0], block[1]);
904
+  const uint8_t endnr = block_buffer_head;
905
+  uint8_t blocknr = block_buffer_tail;
906
+
907
+  // Perform the forward pass
908
+  block_t *current, *previous = NULL;
909
+  while (blocknr != endnr) {
910
+    // Perform the forward pass - Only consider non-sync blocks
911
+    current = &block_buffer[blocknr];
912
+    if (!TEST(current->flag, BLOCK_BIT_SYNC_POSITION)) {
913
+      forward_pass_kernel(previous, current);
914
+      previous = current;
915
+    }
916
+    // Advance to the previous
917
+    blocknr = next_block_index(blocknr);
910
   }
918
   }
911
-  forward_pass_kernel(block[1], block[2]);
912
 }
919
 }
913
 
920
 
914
 /**
921
 /**
917
  * recalculate() after updating the blocks.
924
  * recalculate() after updating the blocks.
918
  */
925
  */
919
 void Planner::recalculate_trapezoids() {
926
 void Planner::recalculate_trapezoids() {
920
-  int8_t block_index = block_buffer_tail;
921
-  block_t *current, *next = NULL;
927
+  uint8_t block_index = block_buffer_tail;
928
+
929
+  // As there could be a sync block in the head of the queue, and the next loop must not
930
+  // recalculate the head block (as it needs to be specially handled), scan backwards until
931
+  // we find the first non SYNC block
932
+  uint8_t head_block_index = block_buffer_head;
933
+  while (head_block_index != block_index) {
934
+
935
+    // Go back (head always point to the first free block)
936
+    uint8_t prev_index = prev_block_index(head_block_index);
937
+
938
+    // Get the pointer to the block
939
+    block_t *prev = &block_buffer[prev_index];
940
+
941
+    // If not dealing with a sync block, we are done. The last block is not a SYNC block
942
+    if (!TEST(prev->flag, BLOCK_BIT_SYNC_POSITION)) break;
943
+
944
+    // Examine the previous block. This and all following are SYNC blocks
945
+    head_block_index = prev_index;
946
+  };
947
+
948
+  // Go from the tail (currently executed block) to the first block, without including it)
949
+  block_t *current = NULL, *next = NULL;
950
+  float current_entry_speed = 0.0, next_entry_speed = 0.0;
951
+  while (block_index != head_block_index) {
922
 
952
 
923
-  while (block_index != block_buffer_head) {
924
-    current = next;
925
     next = &block_buffer[block_index];
953
     next = &block_buffer[block_index];
926
-    if (current) {
927
-      // Recalculate if current block entry or exit junction speed has changed.
928
-      if (TEST(current->flag, BLOCK_BIT_RECALCULATE) || TEST(next->flag, BLOCK_BIT_RECALCULATE)) {
929
-        // NOTE: Entry and exit factors always > 0 by all previous logic operations.
930
-        const float nomr = 1.0 / current->nominal_speed;
931
-        calculate_trapezoid_for_block(current, current->entry_speed * nomr, next->entry_speed * nomr);
932
-        #if ENABLED(LIN_ADVANCE)
933
-          if (current->use_advance_lead) {
934
-            const float comp = current->e_D_ratio * extruder_advance_K * axis_steps_per_mm[E_AXIS];
935
-            current->max_adv_steps = current->nominal_speed * comp;
936
-            current->final_adv_steps = next->entry_speed * comp;
937
-          }
938
-        #endif
939
-        CBI(current->flag, BLOCK_BIT_RECALCULATE); // Reset current only to ensure next trapezoid is computed
954
+
955
+    // Skip sync blocks
956
+    if (!TEST(next->flag, BLOCK_BIT_SYNC_POSITION)) {
957
+      next_entry_speed = SQRT(next->entry_speed_sqr);
958
+
959
+      if (current) {
960
+        // Recalculate if current block entry or exit junction speed has changed.
961
+        if (TEST(current->flag, BLOCK_BIT_RECALCULATE) || TEST(next->flag, BLOCK_BIT_RECALCULATE)) {
962
+          // NOTE: Entry and exit factors always > 0 by all previous logic operations.
963
+          const float current_nominal_speed = SQRT(current->nominal_speed_sqr),
964
+                      nomr = 1.0 / current_nominal_speed;
965
+          calculate_trapezoid_for_block(current, current_entry_speed * nomr, next_entry_speed * nomr);
966
+          #if ENABLED(LIN_ADVANCE)
967
+            if (current->use_advance_lead) {
968
+              const float comp = current->e_D_ratio * extruder_advance_K * axis_steps_per_mm[E_AXIS];
969
+              current->max_adv_steps = current_nominal_speed * comp;
970
+              current->final_adv_steps = next_entry_speed * comp;
971
+            }
972
+          #endif
973
+          CBI(current->flag, BLOCK_BIT_RECALCULATE); // Reset current only to ensure next trapezoid is computed
974
+        }
940
       }
975
       }
976
+
977
+      current = next;
978
+      current_entry_speed = next_entry_speed;
941
     }
979
     }
980
+
942
     block_index = next_block_index(block_index);
981
     block_index = next_block_index(block_index);
943
   }
982
   }
983
+
944
   // Last/newest block in buffer. Exit speed is set with MINIMUM_PLANNER_SPEED. Always recalculated.
984
   // Last/newest block in buffer. Exit speed is set with MINIMUM_PLANNER_SPEED. Always recalculated.
945
   if (next) {
985
   if (next) {
946
-    const float nomr = 1.0 / next->nominal_speed;
947
-    calculate_trapezoid_for_block(next, next->entry_speed * nomr, (MINIMUM_PLANNER_SPEED) * nomr);
986
+    const float next_nominal_speed = SQRT(next->nominal_speed_sqr),
987
+                nomr = 1.0 / next_nominal_speed;
988
+    calculate_trapezoid_for_block(next, next_entry_speed * nomr, (MINIMUM_PLANNER_SPEED) * nomr);
948
     #if ENABLED(LIN_ADVANCE)
989
     #if ENABLED(LIN_ADVANCE)
949
       if (next->use_advance_lead) {
990
       if (next->use_advance_lead) {
950
         const float comp = next->e_D_ratio * extruder_advance_K * axis_steps_per_mm[E_AXIS];
991
         const float comp = next->e_D_ratio * extruder_advance_K * axis_steps_per_mm[E_AXIS];
951
-        next->max_adv_steps = next->nominal_speed * comp;
992
+        next->max_adv_steps = next_nominal_speed * comp;
952
         next->final_adv_steps = (MINIMUM_PLANNER_SPEED) * comp;
993
         next->final_adv_steps = (MINIMUM_PLANNER_SPEED) * comp;
953
       }
994
       }
954
     #endif
995
     #endif
998
     for (uint8_t b = block_buffer_tail; b != block_buffer_head; b = next_block_index(b)) {
1039
     for (uint8_t b = block_buffer_tail; b != block_buffer_head; b = next_block_index(b)) {
999
       block_t* block = &block_buffer[b];
1040
       block_t* block = &block_buffer[b];
1000
       if (block->steps[X_AXIS] || block->steps[Y_AXIS] || block->steps[Z_AXIS]) {
1041
       if (block->steps[X_AXIS] || block->steps[Y_AXIS] || block->steps[Z_AXIS]) {
1001
-        float se = (float)block->steps[E_AXIS] / block->step_event_count * block->nominal_speed; // mm/sec;
1042
+        const float se = (float)block->steps[E_AXIS] / block->step_event_count * SQRT(block->nominal_speed_sqr); // mm/sec;
1002
         NOLESS(high, se);
1043
         NOLESS(high, se);
1003
       }
1044
       }
1004
     }
1045
     }
1299
 
1340
 
1300
 #endif // PLANNER_LEVELING
1341
 #endif // PLANNER_LEVELING
1301
 
1342
 
1343
+void Planner::quick_stop() {
1344
+  // Remove all the queued blocks. Note that this function is NOT
1345
+  // called from the Stepper ISR, so we must consider tail as readonly!
1346
+  // that is why we set head to tail!
1347
+  block_buffer_head = block_buffer_tail;
1348
+
1349
+  #if ENABLED(ULTRA_LCD)
1350
+    // Clear the accumulated runtime
1351
+    clear_block_buffer_runtime();
1352
+  #endif
1353
+
1354
+  // Make sure to drop any attempt of queuing moves for at least 1 second
1355
+  cleaning_buffer_counter = 1000;
1356
+
1357
+  // And stop the stepper ISR
1358
+  stepper.quick_stop();
1359
+}
1360
+
1361
+void Planner::endstop_triggered(const AxisEnum axis) {
1362
+
1363
+  /*NB: This will be called via endstops.update()
1364
+    and endstops.update() can be called from the temperature
1365
+    ISR. So Stepper interrupts are enabled */
1366
+
1367
+  // Disable stepper ISR
1368
+  bool stepper_isr_enabled = STEPPER_ISR_ENABLED();
1369
+  DISABLE_STEPPER_DRIVER_INTERRUPT();
1370
+
1371
+  // Record stepper position
1372
+  stepper.endstop_triggered(axis);
1373
+
1374
+  // Discard the active block that led to the trigger
1375
+  discard_current_block();
1376
+
1377
+  // Discard the CONTINUED block, if any. Note the planner can only queue 1 continued
1378
+  // block after a previous non continued block, as the condition to queue them
1379
+  // is that there are no queued blocks at the time a new block is queued.
1380
+  const bool discard = has_blocks_queued() && TEST(block_buffer[block_buffer_tail].flag, BLOCK_BIT_CONTINUED);
1381
+  if (discard) discard_current_block();
1382
+
1383
+  // Reenable stepper ISR if it was enabled
1384
+  if (stepper_isr_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
1385
+}
1386
+
1387
+float Planner::triggered_position_mm(const AxisEnum axis) {
1388
+  return stepper.triggered_position(axis) * steps_to_mm[axis];
1389
+}
1390
+
1391
+void Planner::finish_and_disable() {
1392
+  while (has_blocks_queued() || cleaning_buffer_counter) idle();
1393
+  disable_all_steppers();
1394
+}
1395
+
1302
 /**
1396
 /**
1303
  * Get an axis position according to stepper position(s)
1397
  * Get an axis position according to stepper position(s)
1304
  * For CORE machines apply translation from ABC to XYZ.
1398
  * For CORE machines apply translation from ABC to XYZ.
1311
 
1405
 
1312
       // Protect the access to the position.
1406
       // Protect the access to the position.
1313
       const bool was_enabled = STEPPER_ISR_ENABLED();
1407
       const bool was_enabled = STEPPER_ISR_ENABLED();
1314
-      DISABLE_STEPPER_DRIVER_INTERRUPT();
1408
+      if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
1315
 
1409
 
1316
       // ((a1+a2)+(a1-a2))/2 -> (a1+a2+a1-a2)/2 -> (a1+a1)/2 -> a1
1410
       // ((a1+a2)+(a1-a2))/2 -> (a1+a2+a1-a2)/2 -> (a1+a1)/2 -> a1
1317
       // ((a1+a2)-(a1-a2))/2 -> (a1+a2-a1+a2)/2 -> (a2+a2)/2 -> a2
1411
       // ((a1+a2)-(a1-a2))/2 -> (a1+a2-a1+a2)/2 -> (a2+a2)/2 -> a2
1333
 /**
1427
 /**
1334
  * Block until all buffered steps are executed / cleaned
1428
  * Block until all buffered steps are executed / cleaned
1335
  */
1429
  */
1336
-void Planner::synchronize() { while (has_blocks_queued() || stepper.cleaning_buffer_counter) idle(); }
1430
+void Planner::synchronize() { while (has_blocks_queued() || cleaning_buffer_counter) idle(); }
1337
 
1431
 
1338
 /**
1432
 /**
1339
  * Planner::_buffer_steps
1433
  * Planner::_buffer_steps
1340
  *
1434
  *
1341
- * Add a new linear movement to the buffer (in terms of steps).
1435
+ * Add a new linear movement to the planner queue (in terms of steps).
1436
+ *
1437
+ *  target      - target position in steps units
1438
+ *  fr_mm_s     - (target) speed of the move
1439
+ *  extruder    - target extruder
1440
+ *  millimeters - the length of the movement, if known
1441
+ *
1442
+ * Returns true if movement was properly queued, false otherwise
1443
+ */
1444
+bool Planner::_buffer_steps(const int32_t (&target)[XYZE]
1445
+  #if HAS_POSITION_FLOAT
1446
+    , const float (&target_float)[XYZE]
1447
+  #endif
1448
+  , float fr_mm_s, const uint8_t extruder, const float &millimeters
1449
+) {
1450
+
1451
+  // If we are cleaning, do not accept queuing of movements
1452
+  if (cleaning_buffer_counter) return false;
1453
+
1454
+  // Wait for the next available block
1455
+  uint8_t next_buffer_head;
1456
+  block_t * const block = get_next_free_block(next_buffer_head);
1457
+
1458
+  // Fill the block with the specified movement
1459
+  if (!_populate_block(block, false, target
1460
+  #if HAS_POSITION_FLOAT
1461
+    , target_float
1462
+  #endif
1463
+    , fr_mm_s, extruder, millimeters
1464
+  )) {
1465
+    // Movement was not queued, probably because it was too short.
1466
+    //  Simply accept that as movement queued and done
1467
+    return true;
1468
+  }
1469
+
1470
+  // Move buffer head
1471
+  block_buffer_head = next_buffer_head;
1472
+
1473
+  // Recalculate and optimize trapezoidal speed profiles
1474
+  recalculate();
1475
+
1476
+  // Movement successfully queued!
1477
+  return true;
1478
+}
1479
+
1480
+/**
1481
+ * Planner::_populate_block
1482
+ *
1483
+ * Fills a new linear movement in the block (in terms of steps).
1342
  *
1484
  *
1343
  *  target      - target position in steps units
1485
  *  target      - target position in steps units
1344
  *  fr_mm_s     - (target) speed of the move
1486
  *  fr_mm_s     - (target) speed of the move
1345
  *  extruder    - target extruder
1487
  *  extruder    - target extruder
1488
+ *
1489
+ * Returns true is movement is acceptable, false otherwise
1346
  */
1490
  */
1347
-void Planner::_buffer_steps(const int32_t (&target)[XYZE]
1491
+bool Planner::_populate_block(block_t * const block, bool split_move,
1492
+    const int32_t (&target)[XYZE]
1348
   #if HAS_POSITION_FLOAT
1493
   #if HAS_POSITION_FLOAT
1349
     , const float (&target_float)[XYZE]
1494
     , const float (&target_float)[XYZE]
1350
   #endif
1495
   #endif
1358
   int32_t de = target[E_AXIS] - position[E_AXIS];
1503
   int32_t de = target[E_AXIS] - position[E_AXIS];
1359
 
1504
 
1360
   /* <-- add a slash to enable
1505
   /* <-- add a slash to enable
1361
-    SERIAL_ECHOPAIR("  _buffer_steps FR:", fr_mm_s);
1506
+    SERIAL_ECHOPAIR("  _populate_block FR:", fr_mm_s);
1362
     SERIAL_ECHOPAIR(" A:", target[A_AXIS]);
1507
     SERIAL_ECHOPAIR(" A:", target[A_AXIS]);
1363
     SERIAL_ECHOPAIR(" (", da);
1508
     SERIAL_ECHOPAIR(" (", da);
1364
     SERIAL_ECHOPAIR(" steps) B:", target[B_AXIS]);
1509
     SERIAL_ECHOPAIR(" steps) B:", target[B_AXIS]);
1427
   const float esteps_float = de * e_factor[extruder];
1572
   const float esteps_float = de * e_factor[extruder];
1428
   const int32_t esteps = ABS(esteps_float) + 0.5;
1573
   const int32_t esteps = ABS(esteps_float) + 0.5;
1429
 
1574
 
1430
-  // Wait for the next available block
1431
-  uint8_t next_buffer_head;
1432
-  block_t * const block = get_next_free_block(next_buffer_head);
1433
-
1434
   // Clear all flags, including the "busy" bit
1575
   // Clear all flags, including the "busy" bit
1435
   block->flag = 0x00;
1576
   block->flag = 0x00;
1436
 
1577
 
1466
   block->step_event_count = MAX4(block->steps[A_AXIS], block->steps[B_AXIS], block->steps[C_AXIS], esteps);
1607
   block->step_event_count = MAX4(block->steps[A_AXIS], block->steps[B_AXIS], block->steps[C_AXIS], esteps);
1467
 
1608
 
1468
   // Bail if this is a zero-length block
1609
   // Bail if this is a zero-length block
1469
-  if (block->step_event_count < MIN_STEPS_PER_SEGMENT) return;
1610
+  if (block->step_event_count < MIN_STEPS_PER_SEGMENT) return false;
1470
 
1611
 
1471
   // For a mixing extruder, get a magnified step_event_count for each
1612
   // For a mixing extruder, get a magnified step_event_count for each
1472
   #if ENABLED(MIXING_EXTRUDER)
1613
   #if ENABLED(MIXING_EXTRUDER)
1706
   #endif
1847
   #endif
1707
 
1848
 
1708
   #if ENABLED(ULTRA_LCD)
1849
   #if ENABLED(ULTRA_LCD)
1709
-    CRITICAL_SECTION_START
1710
-      block_buffer_runtime_us += segment_time_us;
1711
-    CRITICAL_SECTION_END
1850
+    // Protect the access to the position.
1851
+    const bool was_enabled = STEPPER_ISR_ENABLED();
1852
+    if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
1853
+
1854
+    block_buffer_runtime_us += segment_time_us;
1855
+
1856
+    if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
1712
   #endif
1857
   #endif
1713
 
1858
 
1714
-  block->nominal_speed = block->millimeters * inverse_secs;           //   (mm/sec) Always > 0
1859
+  block->nominal_speed_sqr = sq(block->millimeters * inverse_secs);   //   (mm/sec)^2 Always > 0
1715
   block->nominal_rate = CEIL(block->step_event_count * inverse_secs); // (step/sec) Always > 0
1860
   block->nominal_rate = CEIL(block->step_event_count * inverse_secs); // (step/sec) Always > 0
1716
 
1861
 
1717
   #if ENABLED(FILAMENT_WIDTH_SENSOR)
1862
   #if ENABLED(FILAMENT_WIDTH_SENSOR)
1799
   // Correct the speed
1944
   // Correct the speed
1800
   if (speed_factor < 1.0) {
1945
   if (speed_factor < 1.0) {
1801
     LOOP_XYZE(i) current_speed[i] *= speed_factor;
1946
     LOOP_XYZE(i) current_speed[i] *= speed_factor;
1802
-    block->nominal_speed *= speed_factor;
1803
     block->nominal_rate *= speed_factor;
1947
     block->nominal_rate *= speed_factor;
1948
+    block->nominal_speed_sqr = block->nominal_speed_sqr * sq(speed_factor);
1804
   }
1949
   }
1805
 
1950
 
1806
   // Compute and limit the acceleration rate for the trapezoid generator.
1951
   // Compute and limit the acceleration rate for the trapezoid generator.
1895
   block->acceleration_steps_per_s2 = accel;
2040
   block->acceleration_steps_per_s2 = accel;
1896
   block->acceleration = accel / steps_per_mm;
2041
   block->acceleration = accel / steps_per_mm;
1897
   #if DISABLED(BEZIER_JERK_CONTROL)
2042
   #if DISABLED(BEZIER_JERK_CONTROL)
1898
-    block->acceleration_rate = (long)(accel * (4096.0 * 4096.0 / (HAL_STEPPER_TIMER_RATE)));
2043
+    block->acceleration_rate = (uint32_t)(accel * (4096.0 * 4096.0 / (HAL_STEPPER_TIMER_RATE)));
1899
   #endif
2044
   #endif
1900
   #if ENABLED(LIN_ADVANCE)
2045
   #if ENABLED(LIN_ADVANCE)
1901
     if (block->use_advance_lead) {
2046
     if (block->use_advance_lead) {
1902
       block->advance_speed = (HAL_STEPPER_TIMER_RATE) / (extruder_advance_K * block->e_D_ratio * block->acceleration * axis_steps_per_mm[E_AXIS_N]);
2047
       block->advance_speed = (HAL_STEPPER_TIMER_RATE) / (extruder_advance_K * block->e_D_ratio * block->acceleration * axis_steps_per_mm[E_AXIS_N]);
1903
       #if ENABLED(LA_DEBUG)
2048
       #if ENABLED(LA_DEBUG)
1904
-        if (extruder_advance_K * block->e_D_ratio * block->acceleration * 2 < block->nominal_speed * block->e_D_ratio)
2049
+        if (extruder_advance_K * block->e_D_ratio * block->acceleration * 2 < SQRT(block->nominal_speed_sqr) * block->e_D_ratio)
1905
           SERIAL_ECHOLNPGM("More than 2 steps per eISR loop executed.");
2050
           SERIAL_ECHOLNPGM("More than 2 steps per eISR loop executed.");
1906
         if (block->advance_speed < 200)
2051
         if (block->advance_speed < 200)
1907
           SERIAL_ECHOLNPGM("eISR running at > 10kHz.");
2052
           SERIAL_ECHOLNPGM("eISR running at > 10kHz.");
1909
     }
2054
     }
1910
   #endif
2055
   #endif
1911
 
2056
 
1912
-  float vmax_junction; // Initial limit on the segment entry velocity
2057
+  float vmax_junction_sqr; // Initial limit on the segment entry velocity (mm/s)^2
1913
 
2058
 
1914
   #if ENABLED(JUNCTION_DEVIATION)
2059
   #if ENABLED(JUNCTION_DEVIATION)
1915
 
2060
 
1935
      * changed dynamically during operation nor can the line move geometry. This must be kept in
2080
      * changed dynamically during operation nor can the line move geometry. This must be kept in
1936
      * memory in the event of a feedrate override changing the nominal speeds of blocks, which can
2081
      * memory in the event of a feedrate override changing the nominal speeds of blocks, which can
1937
      * change the overall maximum entry speed conditions of all blocks.
2082
      * change the overall maximum entry speed conditions of all blocks.
1938
-     */
2083
+     *
2084
+     * #######
2085
+     * https://github.com/MarlinFirmware/Marlin/issues/10341#issuecomment-388191754
2086
+     *
2087
+     * hoffbaked: on May 10 2018 tuned and improved the GRBL algorithm for Marlin:
2088
+          Okay! It seems to be working good. I somewhat arbitrarily cut it off at 1mm
2089
+          on then on anything with less sides than an octagon. With this, and the
2090
+          reverse pass actually recalculating things, a corner acceleration value
2091
+          of 1000 junction deviation of .05 are pretty reasonable. If the cycles
2092
+          can be spared, a better acos could be used. For all I know, it may be
2093
+          already calculated in a different place. */
1939
 
2094
 
1940
     // Unit vector of previous path line segment
2095
     // Unit vector of previous path line segment
1941
     static float previous_unit_vec[
2096
     static float previous_unit_vec[
1956
     };
2111
     };
1957
 
2112
 
1958
     // Skip first block or when previous_nominal_speed is used as a flag for homing and offset cycles.
2113
     // Skip first block or when previous_nominal_speed is used as a flag for homing and offset cycles.
1959
-    if (moves_queued && !UNEAR_ZERO(previous_nominal_speed)) {
2114
+    if (moves_queued && !UNEAR_ZERO(previous_nominal_speed_sqr)) {
1960
       // Compute cosine of angle between previous and current path. (prev_unit_vec is negative)
2115
       // Compute cosine of angle between previous and current path. (prev_unit_vec is negative)
1961
       // NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity.
2116
       // NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity.
1962
       float junction_cos_theta = -previous_unit_vec[X_AXIS] * unit_vec[X_AXIS]
2117
       float junction_cos_theta = -previous_unit_vec[X_AXIS] * unit_vec[X_AXIS]
1970
       // NOTE: Computed without any expensive trig, sin() or acos(), by trig half angle identity of cos(theta).
2125
       // NOTE: Computed without any expensive trig, sin() or acos(), by trig half angle identity of cos(theta).
1971
       if (junction_cos_theta > 0.999999) {
2126
       if (junction_cos_theta > 0.999999) {
1972
         // For a 0 degree acute junction, just set minimum junction speed.
2127
         // For a 0 degree acute junction, just set minimum junction speed.
1973
-        vmax_junction = MINIMUM_PLANNER_SPEED;
2128
+        vmax_junction_sqr = sq(MINIMUM_PLANNER_SPEED);
1974
       }
2129
       }
1975
       else {
2130
       else {
1976
-        junction_cos_theta = MAX(junction_cos_theta, -0.999999); // Check for numerical round-off to avoid divide by zero.
2131
+        NOLESS(junction_cos_theta, -0.999999); // Check for numerical round-off to avoid divide by zero.
1977
         const float sin_theta_d2 = SQRT(0.5 * (1.0 - junction_cos_theta)); // Trig half angle identity. Always positive.
2132
         const float sin_theta_d2 = SQRT(0.5 * (1.0 - junction_cos_theta)); // Trig half angle identity. Always positive.
1978
 
2133
 
1979
         // TODO: Technically, the acceleration used in calculation needs to be limited by the minimum of the
2134
         // TODO: Technically, the acceleration used in calculation needs to be limited by the minimum of the
1980
         // two junctions. However, this shouldn't be a significant problem except in extreme circumstances.
2135
         // two junctions. However, this shouldn't be a significant problem except in extreme circumstances.
1981
-        vmax_junction = SQRT((block->acceleration * JUNCTION_DEVIATION_FACTOR * sin_theta_d2) / (1.0 - sin_theta_d2));
2136
+        vmax_junction_sqr = (JUNCTION_ACCELERATION_FACTOR * JUNCTION_DEVIATION_FACTOR * sin_theta_d2) / (1.0 - sin_theta_d2);
2137
+        if (block->millimeters < 1.0) {
2138
+
2139
+          // Fast acos approximation, minus the error bar to be safe
2140
+          float junction_theta = (RADIANS(-40) * sq(junction_cos_theta) - RADIANS(50)) * junction_cos_theta + RADIANS(90) - 0.18;
2141
+
2142
+          // If angle is greater than 135 degrees (octagon), find speed for approximate arc
2143
+          if (junction_theta > RADIANS(135)) {
2144
+            const float limit_sqr = block->millimeters / (RADIANS(180) - junction_theta) * JUNCTION_ACCELERATION_FACTOR;
2145
+            NOMORE(vmax_junction_sqr, limit_sqr);
2146
+          }
2147
+        }
1982
       }
2148
       }
1983
 
2149
 
1984
-      vmax_junction = MIN3(vmax_junction, block->nominal_speed, previous_nominal_speed);
2150
+      // Get the lowest speed
2151
+      vmax_junction_sqr = MIN3(vmax_junction_sqr, block->nominal_speed_sqr, previous_nominal_speed_sqr);
1985
     }
2152
     }
1986
     else // Init entry speed to zero. Assume it starts from rest. Planner will correct this later.
2153
     else // Init entry speed to zero. Assume it starts from rest. Planner will correct this later.
1987
-      vmax_junction = 0.0;
2154
+      vmax_junction_sqr = 0.0;
1988
 
2155
 
1989
     COPY(previous_unit_vec, unit_vec);
2156
     COPY(previous_unit_vec, unit_vec);
1990
 
2157
 
2000
     // Exit speed limited by a jerk to full halt of a previous last segment
2167
     // Exit speed limited by a jerk to full halt of a previous last segment
2001
     static float previous_safe_speed;
2168
     static float previous_safe_speed;
2002
 
2169
 
2003
-    float safe_speed = block->nominal_speed;
2170
+    const float nominal_speed = SQRT(block->nominal_speed_sqr);
2171
+    float safe_speed = nominal_speed;
2172
+
2004
     uint8_t limited = 0;
2173
     uint8_t limited = 0;
2005
     LOOP_XYZE(i) {
2174
     LOOP_XYZE(i) {
2006
       const float jerk = ABS(current_speed[i]), maxj = max_jerk[i];
2175
       const float jerk = ABS(current_speed[i]), maxj = max_jerk[i];
2007
       if (jerk > maxj) {
2176
       if (jerk > maxj) {
2008
         if (limited) {
2177
         if (limited) {
2009
-          const float mjerk = maxj * block->nominal_speed;
2178
+          const float mjerk = maxj * nominal_speed;
2010
           if (jerk * safe_speed > mjerk) safe_speed = mjerk / jerk;
2179
           if (jerk * safe_speed > mjerk) safe_speed = mjerk / jerk;
2011
         }
2180
         }
2012
         else {
2181
         else {
2016
       }
2185
       }
2017
     }
2186
     }
2018
 
2187
 
2019
-    if (moves_queued && !UNEAR_ZERO(previous_nominal_speed)) {
2188
+    float vmax_junction;
2189
+    if (moves_queued && !UNEAR_ZERO(previous_nominal_speed_sqr)) {
2020
       // Estimate a maximum velocity allowed at a joint of two successive segments.
2190
       // Estimate a maximum velocity allowed at a joint of two successive segments.
2021
       // If this maximum velocity allowed is lower than the minimum of the entry / exit safe velocities,
2191
       // If this maximum velocity allowed is lower than the minimum of the entry / exit safe velocities,
2022
       // then the machine is not coasting anymore and the safe entry / exit velocities shall be used.
2192
       // then the machine is not coasting anymore and the safe entry / exit velocities shall be used.
2023
 
2193
 
2024
-      // The junction velocity will be shared between successive segments. Limit the junction velocity to their minimum.
2025
-      // Pick the smaller of the nominal speeds. Higher speed shall not be achieved at the junction during coasting.
2026
-      vmax_junction = MIN(block->nominal_speed, previous_nominal_speed);
2027
-
2028
       // Factor to multiply the previous / current nominal velocities to get componentwise limited velocities.
2194
       // Factor to multiply the previous / current nominal velocities to get componentwise limited velocities.
2029
       float v_factor = 1;
2195
       float v_factor = 1;
2030
       limited = 0;
2196
       limited = 0;
2031
 
2197
 
2198
+      // The junction velocity will be shared between successive segments. Limit the junction velocity to their minimum.
2199
+      // Pick the smaller of the nominal speeds. Higher speed shall not be achieved at the junction during coasting.
2200
+      const float previous_nominal_speed = SQRT(previous_nominal_speed_sqr);
2201
+      vmax_junction = MIN(nominal_speed, previous_nominal_speed);
2202
+
2032
       // Now limit the jerk in all axes.
2203
       // Now limit the jerk in all axes.
2033
       const float smaller_speed_factor = vmax_junction / previous_nominal_speed;
2204
       const float smaller_speed_factor = vmax_junction / previous_nominal_speed;
2034
       LOOP_XYZE(axis) {
2205
       LOOP_XYZE(axis) {
2063
       vmax_junction = safe_speed;
2234
       vmax_junction = safe_speed;
2064
 
2235
 
2065
     previous_safe_speed = safe_speed;
2236
     previous_safe_speed = safe_speed;
2237
+    vmax_junction_sqr = sq(vmax_junction);
2238
+
2066
   #endif // Classic Jerk Limiting
2239
   #endif // Classic Jerk Limiting
2067
 
2240
 
2068
   // Max entry speed of this block equals the max exit speed of the previous block.
2241
   // Max entry speed of this block equals the max exit speed of the previous block.
2069
-  block->max_entry_speed = vmax_junction;
2242
+  block->max_entry_speed_sqr = vmax_junction_sqr;
2070
 
2243
 
2071
   // Initialize block entry speed. Compute based on deceleration to user-defined MINIMUM_PLANNER_SPEED.
2244
   // Initialize block entry speed. Compute based on deceleration to user-defined MINIMUM_PLANNER_SPEED.
2072
-  const float v_allowable = max_allowable_speed(-block->acceleration, MINIMUM_PLANNER_SPEED, block->millimeters);
2073
-  // If stepper ISR is disabled, this indicates buffer_segment wants to add a split block.
2074
-  // In this case start with the max. allowed speed to avoid an interrupted first move.
2075
-  block->entry_speed = STEPPER_ISR_ENABLED() ? MINIMUM_PLANNER_SPEED : MIN(vmax_junction, v_allowable);
2245
+  const float v_allowable_sqr = max_allowable_speed_sqr(-block->acceleration, sq(MINIMUM_PLANNER_SPEED), block->millimeters);
2246
+
2247
+  // If we are trying to add a split block, start with the
2248
+  // max. allowed speed to avoid an interrupted first move.
2249
+  block->entry_speed_sqr = !split_move ? sq(MINIMUM_PLANNER_SPEED) : MIN(vmax_junction_sqr, v_allowable_sqr);
2076
 
2250
 
2077
   // Initialize planner efficiency flags
2251
   // Initialize planner efficiency flags
2078
   // Set flag if block will always reach maximum junction speed regardless of entry/exit speeds.
2252
   // Set flag if block will always reach maximum junction speed regardless of entry/exit speeds.
2082
   // block nominal speed limits both the current and next maximum junction speeds. Hence, in both
2256
   // block nominal speed limits both the current and next maximum junction speeds. Hence, in both
2083
   // the reverse and forward planners, the corresponding block junction speed will always be at the
2257
   // the reverse and forward planners, the corresponding block junction speed will always be at the
2084
   // the maximum junction speed and may always be ignored for any speed reduction checks.
2258
   // the maximum junction speed and may always be ignored for any speed reduction checks.
2085
-  block->flag |= block->nominal_speed <= v_allowable ? BLOCK_FLAG_RECALCULATE | BLOCK_FLAG_NOMINAL_LENGTH : BLOCK_FLAG_RECALCULATE;
2259
+  block->flag |= block->nominal_speed_sqr <= v_allowable_sqr ? BLOCK_FLAG_RECALCULATE | BLOCK_FLAG_NOMINAL_LENGTH : BLOCK_FLAG_RECALCULATE;
2086
 
2260
 
2087
   // Update previous path unit_vector and nominal speed
2261
   // Update previous path unit_vector and nominal speed
2088
   COPY(previous_speed, current_speed);
2262
   COPY(previous_speed, current_speed);
2089
-  previous_nominal_speed = block->nominal_speed;
2090
-
2091
-  // Move buffer head
2092
-  block_buffer_head = next_buffer_head;
2263
+  previous_nominal_speed_sqr = block->nominal_speed_sqr;
2093
 
2264
 
2094
-  // Update the position (only when a move was queued)
2265
+  // Update the position
2095
   static_assert(COUNT(target) > 1, "Parameter to _buffer_steps must be (&target)[XYZE]!");
2266
   static_assert(COUNT(target) > 1, "Parameter to _buffer_steps must be (&target)[XYZE]!");
2096
   COPY(position, target);
2267
   COPY(position, target);
2097
   #if HAS_POSITION_FLOAT
2268
   #if HAS_POSITION_FLOAT
2098
     COPY(position_float, target_float);
2269
     COPY(position_float, target_float);
2099
   #endif
2270
   #endif
2100
 
2271
 
2101
-  recalculate();
2102
-
2103
-} // _buffer_steps()
2272
+  // Movement was accepted
2273
+  return true;
2274
+} // _populate_block()
2104
 
2275
 
2105
 /**
2276
 /**
2106
  * Planner::buffer_sync_block
2277
  * Planner::buffer_sync_block
2111
   uint8_t next_buffer_head;
2282
   uint8_t next_buffer_head;
2112
   block_t * const block = get_next_free_block(next_buffer_head);
2283
   block_t * const block = get_next_free_block(next_buffer_head);
2113
 
2284
 
2114
-  block->flag = BLOCK_FLAG_SYNC_POSITION;
2285
+  // Clear block
2286
+  memset(block, 0, sizeof(block_t));
2115
 
2287
 
2116
-  block->steps[A_AXIS] = position[A_AXIS];
2117
-  block->steps[B_AXIS] = position[B_AXIS];
2118
-  block->steps[C_AXIS] = position[C_AXIS];
2119
-  block->steps[E_AXIS] = position[E_AXIS];
2120
-
2121
-  #if ENABLED(LIN_ADVANCE)
2122
-    block->use_advance_lead = false;
2123
-  #endif
2124
-
2125
-  block->nominal_speed   =
2126
-  block->entry_speed     =
2127
-  block->max_entry_speed =
2128
-  block->millimeters     =
2129
-  block->acceleration    = 0;
2288
+  block->flag = BLOCK_FLAG_SYNC_POSITION;
2130
 
2289
 
2131
-  block->step_event_count          =
2132
-  block->nominal_rate              =
2133
-  block->initial_rate              =
2134
-  block->final_rate                =
2135
-  block->acceleration_steps_per_s2 =
2136
-  block->segment_time_us           = 0;
2290
+  block->position[A_AXIS] = position[A_AXIS];
2291
+  block->position[B_AXIS] = position[B_AXIS];
2292
+  block->position[C_AXIS] = position[C_AXIS];
2293
+  block->position[E_AXIS] = position[E_AXIS];
2137
 
2294
 
2138
   block_buffer_head = next_buffer_head;
2295
   block_buffer_head = next_buffer_head;
2139
   stepper.wake_up();
2296
   stepper.wake_up();
2151
  *  extruder    - target extruder
2308
  *  extruder    - target extruder
2152
  *  millimeters - the length of the movement, if known
2309
  *  millimeters - the length of the movement, if known
2153
  */
2310
  */
2154
-void Planner::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*/) {
2311
+bool Planner::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*/) {
2312
+
2313
+  // If we are cleaning, do not accept queuing of movements
2314
+  if (cleaning_buffer_counter) return false;
2315
+
2155
   // When changing extruders recalculate steps corresponding to the E position
2316
   // When changing extruders recalculate steps corresponding to the E position
2156
   #if ENABLED(DISTINCT_E_FACTORS)
2317
   #if ENABLED(DISTINCT_E_FACTORS)
2157
     if (last_extruder != extruder && axis_steps_per_mm[E_AXIS_N] != axis_steps_per_mm[E_AXIS + last_extruder]) {
2318
     if (last_extruder != extruder && axis_steps_per_mm[E_AXIS_N] != axis_steps_per_mm[E_AXIS + last_extruder]) {
2220
       const float between_float[ABCE] = { _BETWEEN_F(A), _BETWEEN_F(B), _BETWEEN_F(C), _BETWEEN_F(E) };
2381
       const float between_float[ABCE] = { _BETWEEN_F(A), _BETWEEN_F(B), _BETWEEN_F(C), _BETWEEN_F(E) };
2221
     #endif
2382
     #endif
2222
 
2383
 
2223
-    DISABLE_STEPPER_DRIVER_INTERRUPT();
2384
+    // The new head value is not assigned yet
2385
+    uint8_t buffer_head = 0;
2386
+    bool added = false;
2224
 
2387
 
2225
-    _buffer_steps(between
2226
-      #if HAS_POSITION_FLOAT
2227
-        , between_float
2228
-      #endif
2229
-      , fr_mm_s, extruder, millimeters * 0.5
2230
-    );
2388
+    uint8_t next_buffer_head;
2389
+    block_t *block = get_next_free_block(next_buffer_head, 2);
2231
 
2390
 
2232
-    const uint8_t next = block_buffer_head;
2391
+    // Fill the block with the specified movement
2392
+    if (
2393
+      _populate_block(block, true, between
2394
+        #if HAS_POSITION_FLOAT
2395
+          , between_float
2396
+        #endif
2397
+        , fr_mm_s, extruder, millimeters * 0.5
2398
+      )
2399
+    ) {
2400
+      // Movement accepted - Point to the next reserved block
2401
+      block = &block_buffer[next_buffer_head];
2402
+
2403
+      // Store into the new to be stored head
2404
+      buffer_head = next_buffer_head;
2405
+      added = true;
2406
+
2407
+      // And advance the pointer to the next unused slot
2408
+      next_buffer_head = next_block_index(next_buffer_head);
2409
+    }
2410
+
2411
+    // Fill the second part of the block with the 2nd part of the movement
2412
+    if (
2413
+      _populate_block(block, true, target
2414
+        #if HAS_POSITION_FLOAT
2415
+          , target_float
2416
+        #endif
2417
+        , fr_mm_s, extruder, millimeters * 0.5
2418
+      )
2419
+    ) {
2420
+      // Movement accepted - If this block is a continuation
2421
+      // of the previous one, mark it as such
2422
+      if (added) SBI(block->flag, BLOCK_BIT_CONTINUED);
2423
+
2424
+      // Store into the new to be stored head
2425
+      buffer_head = next_buffer_head;
2426
+      added = true;
2427
+    }
2233
 
2428
 
2234
-    _buffer_steps(target
2429
+    // If any of the movements was added
2430
+    if (added) {
2431
+
2432
+      // Move buffer head and add all the blocks that were filled
2433
+      // successfully to the movement queue.
2434
+      block_buffer_head = buffer_head;
2435
+
2436
+      // Update the position (only when a move was queued)
2437
+      static_assert(COUNT(target) > 1, "Parameter to _buffer_steps must be (&target)[XYZE]!");
2438
+      COPY(position, target);
2235
       #if HAS_POSITION_FLOAT
2439
       #if HAS_POSITION_FLOAT
2236
-        , target_float
2440
+        COPY(position_float, target_float);
2237
       #endif
2441
       #endif
2238
-      , fr_mm_s, extruder, millimeters * 0.5
2239
-    );
2240
 
2442
 
2241
-    SBI(block_buffer[next].flag, BLOCK_BIT_CONTINUED);
2242
-    ENABLE_STEPPER_DRIVER_INTERRUPT();
2443
+      // Recalculate and optimize trapezoidal speed profiles
2444
+      recalculate();
2445
+    }
2243
   }
2446
   }
2244
-  else
2245
-    _buffer_steps(target
2447
+  else if (
2448
+    !_buffer_steps(target
2246
       #if HAS_POSITION_FLOAT
2449
       #if HAS_POSITION_FLOAT
2247
         , target_float
2450
         , target_float
2248
       #endif
2451
       #endif
2249
       , fr_mm_s, extruder, millimeters
2452
       , fr_mm_s, extruder, millimeters
2250
-    );
2453
+    )
2454
+  ) return false;
2251
 
2455
 
2252
   stepper.wake_up();
2456
   stepper.wake_up();
2253
-
2457
+  return true;
2254
 } // buffer_segment()
2458
 } // buffer_segment()
2255
 
2459
 
2256
 /**
2460
 /**
2277
     position_float[C_AXIS] = c;
2481
     position_float[C_AXIS] = c;
2278
     position_float[E_AXIS] = e;
2482
     position_float[E_AXIS] = e;
2279
   #endif
2483
   #endif
2280
-  previous_nominal_speed = 0.0; // Resets planner junction speeds. Assumes start from rest.
2484
+  previous_nominal_speed_sqr = 0.0; // Resets planner junction speeds. Assumes start from rest.
2281
   ZERO(previous_speed);
2485
   ZERO(previous_speed);
2282
   buffer_sync_block();
2486
   buffer_sync_block();
2283
 }
2487
 }
2298
 }
2502
 }
2299
 
2503
 
2300
 /**
2504
 /**
2301
- * Sync from the stepper positions. (e.g., after an interrupted move)
2302
- */
2303
-void Planner::sync_from_steppers() {
2304
-  LOOP_XYZE(i) {
2305
-    position[i] = stepper.position((AxisEnum)i);
2306
-    #if HAS_POSITION_FLOAT
2307
-      position_float[i] = position[i] * steps_to_mm[i
2308
-        #if ENABLED(DISTINCT_E_FACTORS)
2309
-          + (i == E_AXIS ? active_extruder : 0)
2310
-        #endif
2311
-      ];
2312
-    #endif
2313
-  }
2314
-}
2315
-
2316
-/**
2317
  * Setters for planner position (also setting stepper position).
2505
  * Setters for planner position (also setting stepper position).
2318
  */
2506
  */
2319
 void Planner::set_position_mm(const AxisEnum axis, const float &v) {
2507
 void Planner::set_position_mm(const AxisEnum axis, const float &v) {

+ 144
- 72
Marlin/src/module/planner.h View File

35
 #include "../Marlin.h"
35
 #include "../Marlin.h"
36
 
36
 
37
 #include "motion.h"
37
 #include "motion.h"
38
+#include "../gcode/queue.h"
38
 
39
 
39
 #if ENABLED(DELTA)
40
 #if ENABLED(DELTA)
40
   #include "delta.h"
41
   #include "delta.h"
84
 
85
 
85
   uint8_t flag;                             // Block flags (See BlockFlag enum above)
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
   uint32_t step_event_count;                // The number of step events required to complete this block
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
   #if ENABLED(MIXING_EXTRUDER)
110
   #if ENABLED(MIXING_EXTRUDER)
94
     uint32_t mix_event_count[MIXING_STEPPERS]; // Scaled step_event_count for the mixing steppers
111
     uint32_t mix_event_count[MIXING_STEPPERS]; // Scaled step_event_count for the mixing steppers
95
   #endif
112
   #endif
96
 
113
 
97
   // Settings for the trapezoid generator
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
   #if ENABLED(BEZIER_JERK_CONTROL)
118
   #if ENABLED(BEZIER_JERK_CONTROL)
102
     uint32_t cruise_rate;                   // The actual cruise rate to use, between end of the acceleration phase and start of deceleration phase
119
     uint32_t cruise_rate;                   // The actual cruise rate to use, between end of the acceleration phase and start of deceleration phase
105
     uint32_t acceleration_time_inverse,     // Inverse of acceleration and deceleration periods, expressed as integer. Scale depends on CPU being used
122
     uint32_t acceleration_time_inverse,     // Inverse of acceleration and deceleration periods, expressed as integer. Scale depends on CPU being used
106
              deceleration_time_inverse;
123
              deceleration_time_inverse;
107
   #else
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
   #endif
126
   #endif
110
 
127
 
111
   uint8_t direction_bits;                   // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
128
   uint8_t direction_bits;                   // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
119
     float e_D_ratio;
136
     float e_D_ratio;
120
   #endif
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
   uint32_t nominal_rate,                    // The nominal step rate for this block in step_events/sec
139
   uint32_t nominal_rate,                    // The nominal step rate for this block in step_events/sec
130
            initial_rate,                    // The jerk-adjusted step rate at start of block
140
            initial_rate,                    // The jerk-adjusted step rate at start of block
131
            final_rate,                      // The minimal rate at exit
141
            final_rate,                      // The minimal rate at exit
166
     static block_t block_buffer[BLOCK_BUFFER_SIZE];
176
     static block_t block_buffer[BLOCK_BUFFER_SIZE];
167
     static volatile uint8_t block_buffer_head,      // Index of the next block to be pushed
177
     static volatile uint8_t block_buffer_head,      // Index of the next block to be pushed
168
                             block_buffer_tail;      // Index of the busy block, if any
178
                             block_buffer_tail;      // Index of the busy block, if any
179
+    static int16_t cleaning_buffer_counter;         // A counter to disable queuing of blocks
169
 
180
 
170
     #if ENABLED(DISTINCT_E_FACTORS)
181
     #if ENABLED(DISTINCT_E_FACTORS)
171
       static uint8_t last_extruder;                 // Respond to extruder change
182
       static uint8_t last_extruder;                 // Respond to extruder change
233
       #endif
244
       #endif
234
     #endif
245
     #endif
235
 
246
 
247
+    #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
248
+      static bool abort_on_endstop_hit;
249
+    #endif
250
+
236
   private:
251
   private:
237
 
252
 
238
     /**
253
     /**
247
     static float previous_speed[NUM_AXIS];
262
     static float previous_speed[NUM_AXIS];
248
 
263
 
249
     /**
264
     /**
250
-     * Nominal speed of previous path line segment
265
+     * Nominal speed of previous path line segment (mm/s)^2
251
      */
266
      */
252
-    static float previous_nominal_speed;
267
+    static float previous_nominal_speed_sqr;
253
 
268
 
254
     /**
269
     /**
255
      * Limit where 64bit math is necessary for acceleration calculation
270
      * Limit where 64bit math is necessary for acceleration calculation
308
     // Manage fans, paste pressure, etc.
323
     // Manage fans, paste pressure, etc.
309
     static void check_axes_activity();
324
     static void check_axes_activity();
310
 
325
 
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
     // Update multipliers based on new diameter measurements
326
     // Update multipliers based on new diameter measurements
321
     static void calculate_volumetric_multipliers();
327
     static void calculate_volumetric_multipliers();
322
 
328
 
424
       #define ARG_Z const float &rz
430
       #define ARG_Z const float &rz
425
     #endif
431
     #endif
426
 
432
 
433
+    // Number of moves currently in the planner
434
+    FORCE_INLINE static uint8_t movesplanned() { return BLOCK_MOD(block_buffer_head - block_buffer_tail); }
435
+
436
+    // Remove all blocks from the buffer
437
+    FORCE_INLINE static void clear_block_buffer() { block_buffer_head = block_buffer_tail = 0; }
438
+
439
+    // Check if movement queue is full
440
+    FORCE_INLINE static bool is_full() { return block_buffer_tail == next_block_index(block_buffer_head); }
441
+
442
+    // Get count of movement slots free
443
+    FORCE_INLINE static uint8_t moves_free() { return BLOCK_BUFFER_SIZE - 1 - movesplanned(); }
444
+
427
     /**
445
     /**
428
      * Planner::get_next_free_block
446
      * Planner::get_next_free_block
429
      *
447
      *
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
448
+     * - Get the next head indices (passed by reference)
449
+     * - Wait for the number of spaces to open up in the planner
450
+     * - Return the first head block
433
      */
451
      */
434
-    FORCE_INLINE static block_t* get_next_free_block(uint8_t &next_buffer_head) {
452
+    FORCE_INLINE static block_t* get_next_free_block(uint8_t &next_buffer_head, uint8_t count = 1) {
453
+
454
+      // Wait until there are enough slots free
455
+      while (moves_free() < count) { idle(); }
456
+
457
+      // Return the first available block
435
       next_buffer_head = next_block_index(block_buffer_head);
458
       next_buffer_head = next_block_index(block_buffer_head);
436
-      while (block_buffer_tail == next_buffer_head) idle(); // while (is_full)
437
       return &block_buffer[block_buffer_head];
459
       return &block_buffer[block_buffer_head];
438
     }
460
     }
439
 
461
 
446
      *  fr_mm_s     - (target) speed of the move
468
      *  fr_mm_s     - (target) speed of the move
447
      *  extruder    - target extruder
469
      *  extruder    - target extruder
448
      *  millimeters - the length of the movement, if known
470
      *  millimeters - the length of the movement, if known
471
+     *
472
+     * Returns true if movement was buffered, false otherwise
449
      */
473
      */
450
-    static void _buffer_steps(const int32_t (&target)[XYZE]
474
+    static bool _buffer_steps(const int32_t (&target)[XYZE]
475
+      #if HAS_POSITION_FLOAT
476
+        , const float (&target_float)[XYZE]
477
+      #endif
478
+      , float fr_mm_s, const uint8_t extruder, const float &millimeters=0.0
479
+    );
480
+
481
+    /**
482
+     * Planner::_populate_block
483
+     *
484
+     * Fills a new linear movement in the block (in terms of steps).
485
+     *
486
+     *  target      - target position in steps units
487
+     *  fr_mm_s     - (target) speed of the move
488
+     *  extruder    - target extruder
489
+     *  millimeters - the length of the movement, if known
490
+     *
491
+     * Returns true is movement is acceptable, false otherwise
492
+     */
493
+    static bool _populate_block(block_t * const block, bool split_move,
494
+        const int32_t (&target)[XYZE]
451
       #if HAS_POSITION_FLOAT
495
       #if HAS_POSITION_FLOAT
452
         , const float (&target_float)[XYZE]
496
         , const float (&target_float)[XYZE]
453
       #endif
497
       #endif
472
      *  extruder    - target extruder
516
      *  extruder    - target extruder
473
      *  millimeters - the length of the movement, if known
517
      *  millimeters - the length of the movement, if known
474
      */
518
      */
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);
519
+    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
 
520
 
477
     static void _set_position_mm(const float &a, const float &b, const float &c, const float &e);
521
     static void _set_position_mm(const float &a, const float &b, const float &c, const float &e);
478
 
522
 
489
      *  extruder     - target extruder
533
      *  extruder     - target extruder
490
      *  millimeters  - the length of the movement, if known
534
      *  millimeters  - the length of the movement, if known
491
      */
535
      */
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) {
536
+    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
       #if PLANNER_LEVELING && IS_CARTESIAN
537
       #if PLANNER_LEVELING && IS_CARTESIAN
494
         apply_leveling(rx, ry, rz);
538
         apply_leveling(rx, ry, rz);
495
       #endif
539
       #endif
496
-      buffer_segment(rx, ry, rz, e, fr_mm_s, extruder, millimeters);
540
+      return buffer_segment(rx, ry, rz, e, fr_mm_s, extruder, millimeters);
497
     }
541
     }
498
 
542
 
499
     /**
543
     /**
506
      *  extruder     - target extruder
550
      *  extruder     - target extruder
507
      *  millimeters  - the length of the movement, if known
551
      *  millimeters  - the length of the movement, if known
508
      */
552
      */
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) {
553
+    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
       #if PLANNER_LEVELING
554
       #if PLANNER_LEVELING
511
         float raw[XYZ] = { cart[X_AXIS], cart[Y_AXIS], cart[Z_AXIS] };
555
         float raw[XYZ] = { cart[X_AXIS], cart[Y_AXIS], cart[Z_AXIS] };
512
         apply_leveling(raw);
556
         apply_leveling(raw);
515
       #endif
559
       #endif
516
       #if IS_KINEMATIC
560
       #if IS_KINEMATIC
517
         inverse_kinematics(raw);
561
         inverse_kinematics(raw);
518
-        buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], cart[E_AXIS], fr_mm_s, extruder, millimeters);
562
+        return buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], cart[E_AXIS], fr_mm_s, extruder, millimeters);
519
       #else
563
       #else
520
-        buffer_segment(raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS], cart[E_AXIS], fr_mm_s, extruder, millimeters);
564
+        return buffer_segment(raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS], cart[E_AXIS], fr_mm_s, extruder, millimeters);
521
       #endif
565
       #endif
522
     }
566
     }
523
 
567
 
542
     FORCE_INLINE static void set_e_position_mm(const float &e) { set_position_mm(E_AXIS, e); }
586
     FORCE_INLINE static void set_e_position_mm(const float &e) { set_position_mm(E_AXIS, e); }
543
 
587
 
544
     /**
588
     /**
545
-     * Sync from the stepper positions. (e.g., after an interrupted move)
546
-     */
547
-    static void sync_from_steppers();
548
-
549
-    /**
550
      * Get an axis position according to stepper position(s)
589
      * Get an axis position according to stepper position(s)
551
      * For CORE machines apply translation from ABC to XYZ.
590
      * For CORE machines apply translation from ABC to XYZ.
552
      */
591
      */
557
       FORCE_INLINE static float get_axis_position_degrees(const AxisEnum axis) { return get_axis_position_mm(axis); }
596
       FORCE_INLINE static float get_axis_position_degrees(const AxisEnum axis) { return get_axis_position_mm(axis); }
558
     #endif
597
     #endif
559
 
598
 
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); }
599
+    // Called to force a quick stop of the machine (for example, when an emergency
600
+    // stop is required, or when endstops are hit)
601
+    static void quick_stop();
602
+
603
+    // Called when an endstop is triggered. Causes the machine to stop inmediately
604
+    static void endstop_triggered(const AxisEnum axis);
564
 
605
 
565
-    //
566
-    // Block until all buffered steps are executed
567
-    //
606
+    // Triggered position of an axis in mm (not core-savvy)
607
+    static float triggered_position_mm(const AxisEnum axis);
608
+
609
+    // Block until all buffered steps are executed / cleaned
568
     static void synchronize();
610
     static void synchronize();
569
 
611
 
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);
612
+    // Wait for moves to finish and disable all steppers
613
+    static void finish_and_disable();
614
+
615
+    // Periodic tick to handle cleaning timeouts
616
+    // Called from the Temperature ISR at ~1kHz
617
+    static void tick() {
618
+      if (cleaning_buffer_counter) {
619
+        --cleaning_buffer_counter;
620
+        #if ENABLED(SD_FINISHED_STEPPERRELEASE) && defined(SD_FINISHED_RELEASECOMMAND)
621
+          if (!cleaning_buffer_counter) enqueue_and_echo_commands_P(PSTR(SD_FINISHED_RELEASECOMMAND));
622
+        #endif
623
+      }
577
     }
624
     }
578
 
625
 
579
     /**
626
     /**
580
-     * "Discard" the next block if it's continued.
581
-     * Called after an interrupted move to throw away the rest of the move.
627
+     * Does the buffer have any blocks queued?
582
      */
628
      */
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
-    }
629
+    FORCE_INLINE static bool has_blocks_queued() { return (block_buffer_head != block_buffer_tail); }
588
 
630
 
589
     /**
631
     /**
590
      * The current block. NULL if the buffer is empty.
632
      * The current block. NULL if the buffer is empty.
618
       }
660
       }
619
     }
661
     }
620
 
662
 
663
+    /**
664
+     * "Discard" the block and "release" the memory.
665
+     * Called when the current block is no longer needed.
666
+     * NB: There MUST be a current block to call this function!!
667
+     */
668
+    FORCE_INLINE static void discard_current_block() {
669
+      block_buffer_tail = BLOCK_MOD(block_buffer_tail + 1);
670
+    }
671
+
621
     #if ENABLED(ULTRA_LCD)
672
     #if ENABLED(ULTRA_LCD)
622
 
673
 
623
       static uint16_t block_buffer_runtime() {
674
       static uint16_t block_buffer_runtime() {
624
-        CRITICAL_SECTION_START
625
-          millis_t bbru = block_buffer_runtime_us;
626
-        CRITICAL_SECTION_END
675
+        #ifdef __AVR__
676
+          // Protect the access to the variable. Only required for AVR, as
677
+          //  any 32bit CPU offers atomic access to 32bit variables
678
+          bool was_enabled = STEPPER_ISR_ENABLED();
679
+          if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
680
+        #endif
681
+
682
+        millis_t bbru = block_buffer_runtime_us;
683
+
684
+        #ifdef __AVR__
685
+          // Reenable Stepper ISR
686
+          if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
687
+        #endif
688
+
627
         // To translate µs to ms a division by 1000 would be required.
689
         // To translate µs to ms a division by 1000 would be required.
628
         // We introduce 2.4% error here by dividing by 1024.
690
         // We introduce 2.4% error here by dividing by 1024.
629
         // Doesn't matter because block_buffer_runtime_us is already too small an estimation.
691
         // Doesn't matter because block_buffer_runtime_us is already too small an estimation.
634
       }
696
       }
635
 
697
 
636
       static void clear_block_buffer_runtime() {
698
       static void clear_block_buffer_runtime() {
637
-        CRITICAL_SECTION_START
638
-          block_buffer_runtime_us = 0;
639
-        CRITICAL_SECTION_END
699
+        #ifdef __AVR__
700
+          // Protect the access to the variable. Only required for AVR, as
701
+          //  any 32bit CPU offers atomic access to 32bit variables
702
+          bool was_enabled = STEPPER_ISR_ENABLED();
703
+          if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
704
+        #endif
705
+
706
+        block_buffer_runtime_us = 0;
707
+
708
+        #ifdef __AVR__
709
+          // Reenable Stepper ISR
710
+          if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
711
+        #endif
640
       }
712
       }
641
 
713
 
642
     #endif
714
     #endif
679
     }
751
     }
680
 
752
 
681
     /**
753
     /**
682
-     * Calculate the maximum allowable speed at this point, in order
683
-     * to reach 'target_velocity' using 'acceleration' within a given
754
+     * Calculate the maximum allowable speed squared at this point, in order
755
+     * to reach 'target_velocity_sqr' using 'acceleration' within a given
684
      * 'distance'.
756
      * 'distance'.
685
      */
757
      */
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);
758
+    static float max_allowable_speed_sqr(const float &accel, const float &target_velocity_sqr, const float &distance) {
759
+      return target_velocity_sqr - 2 * accel * distance;
688
     }
760
     }
689
 
761
 
690
     #if ENABLED(BEZIER_JERK_CONTROL)
762
     #if ENABLED(BEZIER_JERK_CONTROL)

+ 4
- 2
Marlin/src/module/planner_bezier.cpp View File

194
     #if HAS_UBL_AND_CURVES
194
     #if HAS_UBL_AND_CURVES
195
       float pos[XYZ] = { bez_target[X_AXIS], bez_target[Y_AXIS], bez_target[Z_AXIS] };
195
       float pos[XYZ] = { bez_target[X_AXIS], bez_target[Y_AXIS], bez_target[Z_AXIS] };
196
       planner.apply_leveling(pos);
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
     #else
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
     #endif
202
     #endif
201
   }
203
   }
202
 }
204
 }

+ 328
- 309
Marlin/src/module/stepper.cpp View File

86
 
86
 
87
 block_t* Stepper::current_block = NULL;  // A pointer to the block currently being traced
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
 #if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
89
 #if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
94
   bool Stepper::performing_homing = false;
90
   bool Stepper::performing_homing = false;
95
 #endif
91
 #endif
101
 // private:
97
 // private:
102
 
98
 
103
 uint8_t Stepper::last_direction_bits = 0;        // The next stepping-bits to be output
99
 uint8_t Stepper::last_direction_bits = 0;        // The next stepping-bits to be output
104
-int16_t Stepper::cleaning_buffer_counter = 0;
105
 
100
 
106
 #if ENABLED(X_DUAL_ENDSTOPS)
101
 #if ENABLED(X_DUAL_ENDSTOPS)
107
   bool Stepper::locked_x_motor = false, Stepper::locked_x2_motor = false;
102
   bool Stepper::locked_x_motor = false, Stepper::locked_x2_motor = false;
118
         Stepper::counter_Z = 0,
113
         Stepper::counter_Z = 0,
119
         Stepper::counter_E = 0;
114
         Stepper::counter_E = 0;
120
 
115
 
121
-volatile uint32_t Stepper::step_events_completed = 0; // The number of step events executed in the current block
116
+uint32_t Stepper::step_events_completed = 0; // The number of step events executed in the current block
122
 
117
 
123
 #if ENABLED(BEZIER_JERK_CONTROL)
118
 #if ENABLED(BEZIER_JERK_CONTROL)
124
   int32_t __attribute__((used)) Stepper::bezier_A __asm__("bezier_A");    // A coefficient in Bézier speed curve with alias for assembler
119
   int32_t __attribute__((used)) Stepper::bezier_A __asm__("bezier_A");    // A coefficient in Bézier speed curve with alias for assembler
132
   bool Stepper::bezier_2nd_half;    // =false If Bézier curve has been initialized or not
127
   bool Stepper::bezier_2nd_half;    // =false If Bézier curve has been initialized or not
133
 #endif
128
 #endif
134
 
129
 
130
+uint32_t Stepper::nextMainISR = 0;
131
+bool Stepper::all_steps_done = false;
132
+
135
 #if ENABLED(LIN_ADVANCE)
133
 #if ENABLED(LIN_ADVANCE)
136
 
134
 
137
   uint32_t Stepper::LA_decelerate_after;
135
   uint32_t Stepper::LA_decelerate_after;
138
 
136
 
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;
137
+  constexpr uint32_t ADV_NEVER = 0xFFFFFFFF;
138
+  uint32_t Stepper::nextAdvanceISR = ADV_NEVER,
139
+           Stepper::eISR_Rate = ADV_NEVER;
144
   uint16_t Stepper::current_adv_steps = 0,
140
   uint16_t Stepper::current_adv_steps = 0,
145
            Stepper::final_adv_steps,
141
            Stepper::final_adv_steps,
146
            Stepper::max_adv_steps;
142
            Stepper::max_adv_steps;
157
 
153
 
158
 #endif // LIN_ADVANCE
154
 #endif // LIN_ADVANCE
159
 
155
 
160
-int32_t Stepper::acceleration_time, Stepper::deceleration_time;
156
+uint32_t Stepper::acceleration_time, Stepper::deceleration_time;
161
 
157
 
162
 volatile int32_t Stepper::count_position[NUM_AXIS] = { 0 };
158
 volatile int32_t Stepper::count_position[NUM_AXIS] = { 0 };
163
 volatile signed char Stepper::count_direction[NUM_AXIS] = { 1, 1, 1, 1 };
159
 volatile signed char Stepper::count_direction[NUM_AXIS] = { 1, 1, 1, 1 };
166
   int32_t Stepper::counter_m[MIXING_STEPPERS];
162
   int32_t Stepper::counter_m[MIXING_STEPPERS];
167
 #endif
163
 #endif
168
 
164
 
165
+uint32_t Stepper::ticks_nominal;
169
 uint8_t Stepper::step_loops, Stepper::step_loops_nominal;
166
 uint8_t Stepper::step_loops, Stepper::step_loops_nominal;
170
 
167
 
171
-hal_timer_t Stepper::OCR1A_nominal;
172
 #if DISABLED(BEZIER_JERK_CONTROL)
168
 #if DISABLED(BEZIER_JERK_CONTROL)
173
-  hal_timer_t Stepper::acc_step_rate; // needed for deceleration start point
169
+  uint32_t Stepper::acc_step_rate; // needed for deceleration start point
174
 #endif
170
 #endif
175
 
171
 
176
 volatile int32_t Stepper::endstops_trigsteps[XYZ];
172
 volatile int32_t Stepper::endstops_trigsteps[XYZ];
379
    *
375
    *
380
    *   Floating point arithmetic execution time cost is prohibitive, so we will transform the math to
376
    *   Floating point arithmetic execution time cost is prohibitive, so we will transform the math to
381
    * use fixed point values to be able to evaluate it in realtime. Assuming a maximum of 250000 steps
377
    * 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
378
+   * per second (driver pulses should at least be 2µS hi/2µS lo), and allocating 2 bits to avoid
383
    * overflows on the evaluation of the Bézier curve, means we can use
379
    * overflows on the evaluation of the Bézier curve, means we can use
384
    *
380
    *
385
    *   t: unsigned Q0.32 (0 <= t < 1) |range 0 to 0xFFFFFFFF unsigned
381
    *   t: unsigned Q0.32 (0 <= t < 1) |range 0 to 0xFFFFFFFF unsigned
1149
 HAL_STEP_TIMER_ISR {
1145
 HAL_STEP_TIMER_ISR {
1150
   HAL_timer_isr_prologue(STEP_TIMER_NUM);
1146
   HAL_timer_isr_prologue(STEP_TIMER_NUM);
1151
 
1147
 
1152
-  #if ENABLED(LIN_ADVANCE)
1153
-    Stepper::advance_isr_scheduler();
1154
-  #else
1155
-    Stepper::isr();
1156
-  #endif
1148
+  // Program timer compare for the maximum period, so it does NOT
1149
+  // flag an interrupt while this ISR is running - So changes from small
1150
+  // periods to big periods are respected and the timer does not reset to 0
1151
+  HAL_timer_set_compare(STEP_TIMER_NUM, HAL_TIMER_TYPE_MAX);
1152
+
1153
+  // Call the ISR scheduler
1154
+  hal_timer_t ticks = Stepper::isr_scheduler();
1155
+
1156
+  // Now 'ticks' contains the period to the next Stepper ISR.
1157
+  // Potential problem: Since the timer continues to run, the requested
1158
+  // compare value may already have passed.
1159
+  //
1160
+  // Assuming at least 6µs between calls to this ISR...
1161
+  // On AVR the ISR epilogue is estimated at 40 instructions - close to 2.5µS.
1162
+  // On ARM the ISR epilogue is estimated at 10 instructions - close to 200nS.
1163
+  // In either case leave at least 4µS for other tasks to execute.
1164
+  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
1165
+  NOLESS(ticks, MAX(minticks, hal_timer_t((STEP_TIMER_MIN_INTERVAL) * (HAL_TICKS_PER_US))));
1166
+
1167
+  // Set the next ISR to fire at the proper time
1168
+  HAL_timer_set_compare(STEP_TIMER_NUM, ticks);
1157
 
1169
 
1158
   HAL_timer_isr_epilogue(STEP_TIMER_NUM);
1170
   HAL_timer_isr_epilogue(STEP_TIMER_NUM);
1159
 }
1171
 }
1164
   #define STEP_MULTIPLY(A,B) MultiU24X32toH16(A, B)
1176
   #define STEP_MULTIPLY(A,B) MultiU24X32toH16(A, B)
1165
 #endif
1177
 #endif
1166
 
1178
 
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)
1179
+hal_timer_t Stepper::isr_scheduler() {
1180
+  uint32_t interval;
1184
 
1181
 
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())) {
1182
+  // Run main stepping pulse phase ISR if we have to
1183
+  if (!nextMainISR) Stepper::stepper_pulse_phase_isr();
1229
 
1184
 
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
-      }
1239
-
1240
-      // Initialize the trapezoid generator from the current block.
1241
-      static int8_t last_extruder = -1;
1242
-
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
1185
+  #if ENABLED(LIN_ADVANCE)
1186
+    // Run linear advance stepper ISR if we have to
1187
+    if (!nextAdvanceISR) nextAdvanceISR = Stepper::advance_isr();
1188
+  #endif
1250
 
1189
 
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
1190
+  // ^== Time critical. NOTHING besides pulse generation should be above here!!!
1257
 
1191
 
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
-      }
1192
+  // Run main stepping block processing ISR if we have to
1193
+  if (!nextMainISR) nextMainISR = Stepper::stepper_block_phase_isr();
1263
 
1194
 
1264
-      // No acceleration / deceleration time elapsed so far
1265
-      acceleration_time = deceleration_time = 0;
1266
-
1267
-      // No step events completed so far
1268
-      step_events_completed = 0;
1195
+  #if ENABLED(LIN_ADVANCE)
1196
+    // Select the closest interval in time
1197
+    interval = (nextAdvanceISR <= nextMainISR)
1198
+      ? nextAdvanceISR
1199
+      : nextMainISR;
1269
 
1200
 
1270
-      // step_rate to timer interval
1271
-      OCR1A_nominal = calc_timer_interval(current_block->nominal_rate);
1201
+  #else // !ENABLED(LIN_ADVANCE)
1272
 
1202
 
1273
-      // make a note of the number of step loops required at nominal speed
1274
-      step_loops_nominal = step_loops;
1275
-
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
1203
+    // The interval is just the remaining time to the stepper ISR
1204
+    interval = nextMainISR;
1205
+  #endif
1280
 
1206
 
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);
1207
+  // Limit the value to the maximum possible value of the timer
1208
+  if (interval > HAL_TIMER_TYPE_MAX)
1209
+    interval = HAL_TIMER_TYPE_MAX;
1284
 
1210
 
1285
-        // We have not started the 2nd half of the trapezoid
1286
-        bezier_2nd_half = false;
1287
-      #endif
1211
+  // Compute the time remaining for the main isr
1212
+  nextMainISR -= interval;
1288
 
1213
 
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
1214
+  #if ENABLED(LIN_ADVANCE)
1215
+    // Compute the time remaining for the advance isr
1216
+    if (nextAdvanceISR != ADV_NEVER)
1217
+      nextAdvanceISR -= interval;
1218
+  #endif
1295
 
1219
 
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
1220
+  return (hal_timer_t)interval;
1221
+}
1300
 
1222
 
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;
1314
-    }
1315
-  }
1223
+// This part of the ISR should ONLY create the pulses for the steppers
1224
+// -- Nothing more, nothing less -- We want to avoid jitter from where
1225
+// the pulses should be generated (when the interrupt triggers) to the
1226
+// time pulses are actually created. So, PLEASE DO NOT PLACE ANY CODE
1227
+// above this line that can conditionally change that time (we are trying
1228
+// to keep the delay between the interrupt triggering and pulse generation
1229
+// as constant as possible!!!!
1230
+void Stepper::stepper_pulse_phase_isr() {
1316
 
1231
 
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
1232
+  // If there is no current block, do nothing
1233
+  if (!current_block) return;
1326
 
1234
 
1327
   // Take multiple steps per interrupt (For high speed moves)
1235
   // Take multiple steps per interrupt (For high speed moves)
1328
-  bool all_steps_done = false;
1236
+  all_steps_done = false;
1329
   for (uint8_t i = step_loops; i--;) {
1237
   for (uint8_t i = step_loops; i--;) {
1330
 
1238
 
1331
     #define _COUNTER(AXIS) counter_## AXIS
1239
     #define _COUNTER(AXIS) counter_## AXIS
1520
     #endif
1428
     #endif
1521
 
1429
 
1522
   } // steps_loop
1430
   } // steps_loop
1431
+}
1523
 
1432
 
1524
-  // Calculate new timer value
1525
-  if (step_events_completed <= (uint32_t)current_block->accelerate_until) {
1433
+// This is the last half of the stepper interrupt: This one processes and
1434
+// properly schedules blocks from the planner. This is executed after creating
1435
+// the step pulses, so it is not time critical, as pulses are already done.
1526
 
1436
 
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
1437
+uint32_t Stepper::stepper_block_phase_isr() {
1537
 
1438
 
1538
-    // step_rate to timer interval
1539
-    const hal_timer_t interval = calc_timer_interval(acc_step_rate);
1439
+  // If no queued movements, just wait 1ms for the next move
1440
+  uint32_t interval = (HAL_STEPPER_TIMER_RATE / 1000);
1540
 
1441
 
1541
-    SPLIT(interval);  // split step into multiple ISRs if larger than ENDSTOP_NOMINAL_OCR_VAL
1542
-    _NEXT_ISR(ocr_val);
1442
+  // If there is a current block
1443
+  if (current_block) {
1543
 
1444
 
1544
-    acceleration_time += interval;
1445
+    // Calculate new timer value
1446
+    if (step_events_completed <= current_block->accelerate_until) {
1545
 
1447
 
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;
1448
+      #if ENABLED(BEZIER_JERK_CONTROL)
1449
+        // Get the next speed to use (Jerk limited!)
1450
+        uint32_t acc_step_rate =
1451
+          acceleration_time < current_block->acceleration_time
1452
+            ? _eval_bezier_curve(acceleration_time)
1453
+            : current_block->cruise_rate;
1454
+      #else
1455
+        acc_step_rate = STEP_MULTIPLY(acceleration_time, current_block->acceleration_rate) + current_block->initial_rate;
1456
+        NOMORE(acc_step_rate, current_block->nominal_rate);
1457
+      #endif
1458
+
1459
+      // step_rate to timer interval
1460
+      interval = calc_timer_interval(acc_step_rate);
1461
+      acceleration_time += interval;
1462
+
1463
+      #if ENABLED(LIN_ADVANCE)
1464
+        if (current_block->use_advance_lead) {
1465
+          if (step_events_completed == step_loops || (e_steps && eISR_Rate != current_block->advance_speed)) {
1466
+            nextAdvanceISR = 0; // Wake up eISR on first acceleration loop and fire ISR if final adv_rate is reached
1467
+            eISR_Rate = current_block->advance_speed;
1468
+          }
1551
         }
1469
         }
1552
-      }
1553
-      else {
1554
-        eISR_Rate = ADV_NEVER;
1555
-        if (e_steps) nextAdvanceISR = 0;
1556
-      }
1557
-    #endif // LIN_ADVANCE
1470
+        else {
1471
+          eISR_Rate = ADV_NEVER;
1472
+          if (e_steps) nextAdvanceISR = 0;
1473
+        }
1474
+      #endif // LIN_ADVANCE
1475
+    }
1476
+    else if (step_events_completed > current_block->decelerate_after) {
1477
+      uint32_t step_rate;
1478
+
1479
+      #if ENABLED(BEZIER_JERK_CONTROL)
1480
+        // If this is the 1st time we process the 2nd half of the trapezoid...
1481
+        if (!bezier_2nd_half) {
1482
+          // Initialize the Bézier speed curve
1483
+          _calc_bezier_curve_coeffs(current_block->cruise_rate, current_block->final_rate, current_block->deceleration_time_inverse);
1484
+          bezier_2nd_half = true;
1485
+        }
1486
+
1487
+        // Calculate the next speed to use
1488
+        step_rate = deceleration_time < current_block->deceleration_time
1489
+          ? _eval_bezier_curve(deceleration_time)
1490
+          : current_block->final_rate;
1491
+      #else
1492
+
1493
+        // Using the old trapezoidal control
1494
+        step_rate = STEP_MULTIPLY(deceleration_time, current_block->acceleration_rate);
1495
+        if (step_rate < acc_step_rate) { // Still decelerating?
1496
+          step_rate = acc_step_rate - step_rate;
1497
+          NOLESS(step_rate, current_block->final_rate);
1498
+        }
1499
+        else
1500
+          step_rate = current_block->final_rate;
1501
+      #endif
1502
+
1503
+      // step_rate to timer interval
1504
+      interval = calc_timer_interval(step_rate);
1505
+      deceleration_time += interval;
1506
+
1507
+      #if ENABLED(LIN_ADVANCE)
1508
+        if (current_block->use_advance_lead) {
1509
+          if (step_events_completed <= current_block->decelerate_after + step_loops || (e_steps && eISR_Rate != current_block->advance_speed)) {
1510
+            nextAdvanceISR = 0; // Wake up eISR on first deceleration loop
1511
+            eISR_Rate = current_block->advance_speed;
1512
+          }
1513
+        }
1514
+        else {
1515
+          eISR_Rate = ADV_NEVER;
1516
+          if (e_steps) nextAdvanceISR = 0;
1517
+        }
1518
+      #endif // LIN_ADVANCE
1519
+    }
1520
+    else {
1521
+
1522
+      #if ENABLED(LIN_ADVANCE)
1523
+        // If there are any esteps, fire the next advance_isr "now"
1524
+        if (e_steps && eISR_Rate != current_block->advance_speed) nextAdvanceISR = 0;
1525
+      #endif
1526
+
1527
+      // The timer interval is just the nominal value for the nominal speed
1528
+      interval = ticks_nominal;
1529
+
1530
+      // Ensure this runs at the correct step rate, even if it just came off an acceleration
1531
+      step_loops = step_loops_nominal;
1532
+    }
1533
+
1534
+    // If current block is finished, reset pointer
1535
+    if (all_steps_done) {
1536
+      current_block = NULL;
1537
+      planner.discard_current_block();
1538
+    }
1558
   }
1539
   }
1559
-  else if (step_events_completed > (uint32_t)current_block->decelerate_after) {
1560
-    hal_timer_t step_rate;
1561
 
1540
 
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) {
1541
+  // If there is no current block at this point, attempt to pop one from the buffer
1542
+  // and prepare its movement
1543
+  if (!current_block) {
1544
+
1545
+    // Anything in the buffer?
1546
+    if ((current_block = planner.get_current_block())) {
1565
 
1547
 
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;
1548
+      // Sync block? Sync the stepper counts and return
1549
+      while (TEST(current_block->flag, BLOCK_BIT_SYNC_POSITION)) {
1550
+        _set_position(
1551
+          current_block->position[A_AXIS], current_block->position[B_AXIS],
1552
+          current_block->position[C_AXIS], current_block->position[E_AXIS]
1553
+        );
1554
+        planner.discard_current_block();
1555
+
1556
+        // Try to get a new block
1557
+        if (!(current_block = planner.get_current_block()))
1558
+          return interval; // No more queued movements!
1569
       }
1559
       }
1570
 
1560
 
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
1561
+      // Initialize the trapezoid generator from the current block.
1562
+      static int8_t last_extruder = -1;
1563
+
1564
+      #if ENABLED(LIN_ADVANCE)
1565
+        #if E_STEPPERS > 1
1566
+          if (current_block->active_extruder != last_extruder) {
1567
+            current_adv_steps = 0; // If the now active extruder wasn't in use during the last move, its pressure is most likely gone.
1568
+            LA_active_extruder = current_block->active_extruder;
1569
+          }
1570
+        #endif
1576
 
1571
 
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);
1572
+        if ((use_advance_lead = current_block->use_advance_lead)) {
1573
+          LA_decelerate_after = current_block->decelerate_after;
1574
+          final_adv_steps = current_block->final_adv_steps;
1575
+          max_adv_steps = current_block->max_adv_steps;
1576
+        }
1577
+      #endif
1578
+
1579
+      if (current_block->direction_bits != last_direction_bits || current_block->active_extruder != last_extruder) {
1580
+        last_direction_bits = current_block->direction_bits;
1581
+        last_extruder = current_block->active_extruder;
1582
+        set_directions();
1582
       }
1583
       }
1583
-      else
1584
-        step_rate = current_block->final_rate;
1585
 
1584
 
1586
-    #endif
1585
+      // No acceleration / deceleration time elapsed so far
1586
+      acceleration_time = deceleration_time = 0;
1587
 
1587
 
1588
-    // step_rate to timer interval
1589
-    const hal_timer_t interval = calc_timer_interval(step_rate);
1588
+      // No step events completed so far
1589
+      step_events_completed = 0;
1590
 
1590
 
1591
-    SPLIT(interval);  // split step into multiple ISRs if larger than ENDSTOP_NOMINAL_OCR_VAL
1592
-    _NEXT_ISR(ocr_val);
1591
+      // step_rate to timer interval for the nominal speed
1592
+      ticks_nominal = calc_timer_interval(current_block->nominal_rate);
1593
 
1593
 
1594
-    deceleration_time += interval;
1594
+      // make a note of the number of step loops required at nominal speed
1595
+      step_loops_nominal = step_loops;
1595
 
1596
 
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 {
1597
+      #if DISABLED(BEZIER_JERK_CONTROL)
1598
+        // Set as deceleration point the initial rate of the block
1599
+        acc_step_rate = current_block->initial_rate;
1600
+      #endif
1610
 
1601
 
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
1602
+      #if ENABLED(BEZIER_JERK_CONTROL)
1603
+        // Initialize the Bézier speed curve
1604
+        _calc_bezier_curve_coeffs(current_block->initial_rate, current_block->cruise_rate, current_block->acceleration_time_inverse);
1615
 
1605
 
1616
-    SPLIT(OCR1A_nominal);  // split step into multiple ISRs if larger than ENDSTOP_NOMINAL_OCR_VAL
1617
-    _NEXT_ISR(ocr_val);
1606
+        // We have not started the 2nd half of the trapezoid
1607
+        bezier_2nd_half = false;
1608
+      #endif
1618
 
1609
 
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
-  }
1610
+      // Initialize Bresenham counters to 1/2 the ceiling
1611
+      counter_X = counter_Y = counter_Z = counter_E = -((int32_t)(current_block->step_event_count >> 1));
1612
+      #if ENABLED(MIXING_EXTRUDER)
1613
+        MIXING_STEPPERS_LOOP(i)
1614
+          counter_m[i] = -(current_block->mix_event_count[i] >> 1);
1615
+      #endif
1622
 
1616
 
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
1617
+      #if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
1618
+        e_hit = 2; // Needed for the case an endstop is already triggered before the new move begins.
1619
+                   // No 'change' can be detected.
1620
+      #endif
1627
 
1621
 
1628
-  // If current block is finished, reset pointer
1629
-  if (all_steps_done) {
1630
-    current_block = NULL;
1631
-    planner.discard_current_block();
1622
+      #if ENABLED(Z_LATE_ENABLE)
1623
+        // If delayed Z enable, enable it now. This option will severely interfere with
1624
+        //  timing between pulses when chaining motion between blocks, and it could lead
1625
+        //  to lost steps in both X and Y axis, so avoid using it unless strictly necessary!!
1626
+        if (current_block->steps[Z_AXIS]) enable_Z();
1627
+      #endif
1628
+    }
1632
   }
1629
   }
1630
+
1631
+  // Return the interval to wait
1632
+  return interval;
1633
 }
1633
 }
1634
 
1634
 
1635
 #if ENABLED(LIN_ADVANCE)
1635
 #if ENABLED(LIN_ADVANCE)
1638
   #define EXTRA_CYCLES_E (STEP_PULSE_CYCLES - (CYCLES_EATEN_E))
1638
   #define EXTRA_CYCLES_E (STEP_PULSE_CYCLES - (CYCLES_EATEN_E))
1639
 
1639
 
1640
   // Timer interrupt for E. e_steps is set in the main routine;
1640
   // Timer interrupt for E. e_steps is set in the main routine;
1641
-
1642
-  void Stepper::advance_isr() {
1641
+  uint32_t Stepper::advance_isr() {
1642
+    uint32_t interval;
1643
 
1643
 
1644
     #if ENABLED(MK2_MULTIPLEXER) // For SNMM even-numbered steppers are reversed
1644
     #if ENABLED(MK2_MULTIPLEXER) // For SNMM even-numbered steppers are reversed
1645
       #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)
1645
       #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
       if (step_events_completed > LA_decelerate_after && current_adv_steps > final_adv_steps) {
1700
       if (step_events_completed > LA_decelerate_after && current_adv_steps > final_adv_steps) {
1701
         e_steps--;
1701
         e_steps--;
1702
         current_adv_steps--;
1702
         current_adv_steps--;
1703
-        nextAdvanceISR = eISR_Rate;
1703
+        interval = eISR_Rate;
1704
       }
1704
       }
1705
       else if (step_events_completed < LA_decelerate_after && current_adv_steps < max_adv_steps) {
1705
       else if (step_events_completed < LA_decelerate_after && current_adv_steps < max_adv_steps) {
1706
              //step_events_completed <= (uint32_t)current_block->accelerate_until) {
1706
              //step_events_completed <= (uint32_t)current_block->accelerate_until) {
1707
         e_steps++;
1707
         e_steps++;
1708
         current_adv_steps++;
1708
         current_adv_steps++;
1709
-        nextAdvanceISR = eISR_Rate;
1709
+        interval = eISR_Rate;
1710
       }
1710
       }
1711
       else {
1711
       else {
1712
-        nextAdvanceISR = ADV_NEVER;
1712
+        interval = ADV_NEVER;
1713
         eISR_Rate = ADV_NEVER;
1713
         eISR_Rate = ADV_NEVER;
1714
       }
1714
       }
1715
     }
1715
     }
1716
     else
1716
     else
1717
-      nextAdvanceISR = ADV_NEVER;
1717
+      interval = ADV_NEVER;
1718
 
1718
 
1719
     switch (LA_active_extruder) {
1719
     switch (LA_active_extruder) {
1720
       case 0: SET_E_STEP_DIR(0); break;
1720
       case 0: SET_E_STEP_DIR(0); break;
1787
       #endif
1787
       #endif
1788
 
1788
 
1789
     } // e_steps
1789
     } // e_steps
1790
-  }
1791
 
1790
 
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
-
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);
1791
+    return interval;
1821
   }
1792
   }
1822
-
1823
 #endif // LIN_ADVANCE
1793
 #endif // LIN_ADVANCE
1824
 
1794
 
1825
 void Stepper::init() {
1795
 void Stepper::init() {
2048
  * Get a stepper's position in steps.
2018
  * Get a stepper's position in steps.
2049
  */
2019
  */
2050
 int32_t Stepper::position(const AxisEnum axis) {
2020
 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
-}
2021
+  #ifdef __AVR__
2022
+    // Protect the access to the position. Only required for AVR, as
2023
+    //  any 32bit CPU offers atomic access to 32bit variables
2024
+    const bool was_enabled = STEPPER_ISR_ENABLED();
2025
+    if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
2026
+  #endif
2056
 
2027
 
2057
-void Stepper::finish_and_disable() {
2058
-  planner.synchronize();
2059
-  disable_all_steppers();
2028
+  int32_t v = count_position[axis];
2029
+
2030
+  #ifdef __AVR__
2031
+    // Reenable Stepper ISR
2032
+    if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
2033
+  #endif
2034
+  return v;
2060
 }
2035
 }
2061
 
2036
 
2062
 void Stepper::quick_stop() {
2037
 void Stepper::quick_stop() {
2038
+  const bool was_enabled = STEPPER_ISR_ENABLED();
2063
   DISABLE_STEPPER_DRIVER_INTERRUPT();
2039
   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();
2071
-  #endif
2040
+
2041
+  if (current_block) {
2042
+    step_events_completed = current_block->step_event_count;
2043
+    current_block = NULL;
2044
+  }
2045
+
2046
+  if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
2047
+}
2048
+
2049
+void Stepper::kill_current_block() {
2050
+  const bool was_enabled = STEPPER_ISR_ENABLED();
2051
+  DISABLE_STEPPER_DRIVER_INTERRUPT();
2052
+
2053
+  if (current_block)
2054
+    step_events_completed = current_block->step_event_count;
2055
+
2056
+  if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
2072
 }
2057
 }
2073
 
2058
 
2074
 void Stepper::endstop_triggered(const AxisEnum axis) {
2059
 void Stepper::endstop_triggered(const AxisEnum axis) {
2060
+  const bool was_enabled = STEPPER_ISR_ENABLED();
2061
+  if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
2075
 
2062
 
2076
   #if IS_CORE
2063
   #if IS_CORE
2077
 
2064
 
2086
 
2073
 
2087
   #endif // !COREXY && !COREXZ && !COREYZ
2074
   #endif // !COREXY && !COREXZ && !COREYZ
2088
 
2075
 
2089
-  kill_current_block();
2090
-  cleaning_buffer_counter = -1; // Discard the rest of the move
2076
+  // Discard the rest of the move if there is a current block
2077
+  if (current_block) {
2078
+
2079
+    // Kill the current block being executed
2080
+    step_events_completed = current_block->step_event_count;
2081
+
2082
+    // Prep to get a new block after cleaning
2083
+    current_block = NULL;
2084
+  }
2085
+
2086
+  if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
2087
+}
2088
+
2089
+int32_t Stepper::triggered_position(const AxisEnum axis) {
2090
+  #ifdef __AVR__
2091
+    // Protect the access to the position. Only required for AVR, as
2092
+    //  any 32bit CPU offers atomic access to 32bit variables
2093
+    const bool was_enabled = STEPPER_ISR_ENABLED();
2094
+    if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
2095
+  #endif
2096
+
2097
+  const int32_t v = endstops_trigsteps[axis];
2098
+
2099
+  #ifdef __AVR__
2100
+    // Reenable Stepper ISR
2101
+    if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
2102
+  #endif
2103
+
2104
+  return v;
2091
 }
2105
 }
2092
 
2106
 
2093
 void Stepper::report_positions() {
2107
 void Stepper::report_positions() {
2094
-  CRITICAL_SECTION_START;
2108
+
2109
+  // Protect the access to the position.
2110
+  const bool was_enabled = STEPPER_ISR_ENABLED();
2111
+  if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
2112
+
2095
   const int32_t xpos = count_position[X_AXIS],
2113
   const int32_t xpos = count_position[X_AXIS],
2096
                 ypos = count_position[Y_AXIS],
2114
                 ypos = count_position[Y_AXIS],
2097
                 zpos = count_position[Z_AXIS];
2115
                 zpos = count_position[Z_AXIS];
2098
-  CRITICAL_SECTION_END;
2116
+
2117
+  if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
2099
 
2118
 
2100
   #if CORE_IS_XY || CORE_IS_XZ || IS_DELTA || IS_SCARA
2119
   #if CORE_IS_XY || CORE_IS_XZ || IS_DELTA || IS_SCARA
2101
     SERIAL_PROTOCOLPGM(MSG_COUNT_A);
2120
     SERIAL_PROTOCOLPGM(MSG_COUNT_A);

+ 42
- 98
Marlin/src/module/stepper.h View File

62
 
62
 
63
     static block_t* current_block;  // A pointer to the block currently being traced
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
     #if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
65
     #if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
70
       static bool performing_homing;
66
       static bool performing_homing;
71
     #endif
67
     #endif
77
       static uint32_t motor_current_setting[3];
73
       static uint32_t motor_current_setting[3];
78
     #endif
74
     #endif
79
 
75
 
80
-    static int16_t cleaning_buffer_counter;
81
-
82
   private:
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
95
 
89
 
96
     // Counter variables for the Bresenham line tracer
90
     // Counter variables for the Bresenham line tracer
97
     static int32_t counter_X, counter_Y, counter_Z, counter_E;
91
     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
92
+    static uint32_t step_events_completed; // The number of step events executed in the current block
99
 
93
 
100
     #if ENABLED(BEZIER_JERK_CONTROL)
94
     #if ENABLED(BEZIER_JERK_CONTROL)
101
       static int32_t bezier_A,     // A coefficient in Bézier speed curve
95
       static int32_t bezier_A,     // A coefficient in Bézier speed curve
109
       static bool bezier_2nd_half; // If Bézier curve has been initialized or not
103
       static bool bezier_2nd_half; // If Bézier curve has been initialized or not
110
     #endif
104
     #endif
111
 
105
 
106
+    static uint32_t nextMainISR;   // time remaining for the next Step ISR
107
+    static bool all_steps_done;    // all steps done
108
+
112
     #if ENABLED(LIN_ADVANCE)
109
     #if ENABLED(LIN_ADVANCE)
113
 
110
 
114
       static uint32_t LA_decelerate_after; // Copy from current executed block. Needed because current_block is set to NULL "too early".
111
       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;
112
+      static uint32_t nextAdvanceISR, eISR_Rate;
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".
113
       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
       static int8_t e_steps;
114
       static int8_t e_steps;
119
       static bool use_advance_lead;
115
       static bool use_advance_lead;
120
       #if E_STEPPERS > 1
116
       #if E_STEPPERS > 1
123
         static constexpr int8_t LA_active_extruder = 0;
119
         static constexpr int8_t LA_active_extruder = 0;
124
       #endif
120
       #endif
125
 
121
 
126
-    #else // !LIN_ADVANCE
127
-
128
-      #define _NEXT_ISR(T) HAL_timer_set_compare(STEP_TIMER_NUM, T);
122
+    #endif // LIN_ADVANCE
129
 
123
 
130
-    #endif // !LIN_ADVANCE
131
-
132
-    static int32_t acceleration_time, deceleration_time;
124
+    static uint32_t acceleration_time, deceleration_time;
133
     static uint8_t step_loops, step_loops_nominal;
125
     static uint8_t step_loops, step_loops_nominal;
134
 
126
 
135
-    static hal_timer_t OCR1A_nominal;
127
+    static uint32_t ticks_nominal;
136
     #if DISABLED(BEZIER_JERK_CONTROL)
128
     #if DISABLED(BEZIER_JERK_CONTROL)
137
-      static hal_timer_t acc_step_rate; // needed for deceleration start point
129
+      static uint32_t acc_step_rate; // needed for deceleration start point
138
     #endif
130
     #endif
139
 
131
 
140
     static volatile int32_t endstops_trigsteps[XYZ];
132
     static volatile int32_t endstops_trigsteps[XYZ];
167
     //
159
     //
168
     Stepper() { };
160
     Stepper() { };
169
 
161
 
170
-    //
171
     // Initialize stepper hardware
162
     // Initialize stepper hardware
172
-    //
173
     static void init();
163
     static void init();
174
 
164
 
175
-    //
176
     // Interrupt Service Routines
165
     // Interrupt Service Routines
177
-    //
178
-
179
-    static void isr();
180
 
166
 
181
-    #if ENABLED(LIN_ADVANCE)
182
-      static void advance_isr();
183
-      static void advance_isr_scheduler();
184
-    #endif
167
+    // The ISR scheduler
168
+    static hal_timer_t isr_scheduler();
185
 
169
 
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);
170
+    // The stepper pulse phase ISR
171
+    static void stepper_pulse_phase_isr();
190
 
172
 
191
-    FORCE_INLINE static void _set_position(const AxisEnum a, const int32_t &v) { count_position[a] = v; }
173
+    // The stepper block processing phase ISR
174
+    static uint32_t stepper_block_phase_isr();
192
 
175
 
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();
176
+    #if ENABLED(LIN_ADVANCE)
177
+      // The Linear advance stepper ISR
178
+      static uint32_t advance_isr();
179
+    #endif
220
 
180
 
221
-    //
222
     // Get the position of a stepper, in steps
181
     // Get the position of a stepper, in steps
223
-    //
224
     static int32_t position(const AxisEnum axis);
182
     static int32_t position(const AxisEnum axis);
225
 
183
 
226
-    //
227
     // Report the positions of the steppers, in steps
184
     // Report the positions of the steppers, in steps
228
-    //
229
     static void report_positions();
185
     static void report_positions();
230
 
186
 
231
-    //
232
     // The stepper subsystem goes to sleep when it runs out of things to execute. Call this
187
     // The stepper subsystem goes to sleep when it runs out of things to execute. Call this
233
     // to notify the subsystem that it is time to go to work.
188
     // to notify the subsystem that it is time to go to work.
234
-    //
235
     static void wake_up();
189
     static void wake_up();
236
 
190
 
237
-    //
238
-    // Wait for moves to finish and disable all steppers
239
-    //
240
-    static void finish_and_disable();
241
-
242
-    //
243
-    // Quickly stop all steppers and clear the blocks queue
244
-    //
191
+    // Quickly stop all steppers
245
     static void quick_stop();
192
     static void quick_stop();
246
 
193
 
247
-    //
248
     // The direction of a single motor
194
     // The direction of a single motor
249
-    //
250
     FORCE_INLINE static bool motor_direction(const AxisEnum axis) { return TEST(last_direction_bits, axis); }
195
     FORCE_INLINE static bool motor_direction(const AxisEnum axis) { return TEST(last_direction_bits, axis); }
251
 
196
 
197
+    // Kill current block
198
+    static void kill_current_block();
199
+
200
+    // Handle a triggered endstop
201
+    static void endstop_triggered(const AxisEnum axis);
202
+
203
+    // Triggered position of an axis in steps
204
+    static int32_t triggered_position(const AxisEnum axis);
205
+
252
     #if HAS_DIGIPOTSS || HAS_MOTOR_CURRENT_PWM
206
     #if HAS_DIGIPOTSS || HAS_MOTOR_CURRENT_PWM
253
       static void digitalPotWrite(const int16_t address, const int16_t value);
207
       static void digitalPotWrite(const int16_t address, const int16_t value);
254
       static void digipot_current(const uint8_t driver, const int16_t current);
208
       static void digipot_current(const uint8_t driver, const int16_t current);
280
       static void babystep(const AxisEnum axis, const bool direction); // perform a short step with a single stepper motor, outside of any convention
234
       static void babystep(const AxisEnum axis, const bool direction); // perform a short step with a single stepper motor, outside of any convention
281
     #endif
235
     #endif
282
 
236
 
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
     #if HAS_MOTOR_CURRENT_PWM
237
     #if HAS_MOTOR_CURRENT_PWM
300
       static void refresh_motor_power();
238
       static void refresh_motor_power();
301
     #endif
239
     #endif
302
 
240
 
303
   private:
241
   private:
304
 
242
 
305
-    FORCE_INLINE static hal_timer_t calc_timer_interval(hal_timer_t step_rate) {
306
-      hal_timer_t timer;
243
+    // Set the current position in steps
244
+    static void _set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e);
245
+
246
+    // Set direction bits for all steppers
247
+    static void set_directions();
248
+
249
+    FORCE_INLINE static uint32_t calc_timer_interval(uint32_t step_rate) {
250
+      uint32_t timer;
307
 
251
 
308
       NOMORE(step_rate, MAX_STEP_FREQUENCY);
252
       NOMORE(step_rate, MAX_STEP_FREQUENCY);
309
 
253
 
310
-      // TODO: HAL: tidy this up, use condtionals_post.h
254
+      // TODO: HAL: tidy this up, use Conditionals_post.h
311
       #ifdef CPU_32_BIT
255
       #ifdef CPU_32_BIT
312
         #if ENABLED(DISABLE_MULTI_STEPPING)
256
         #if ENABLED(DISABLE_MULTI_STEPPING)
313
           step_loops = 1;
257
           step_loops = 1;
348
         step_rate -= F_CPU / 500000; // Correct for minimal speed
292
         step_rate -= F_CPU / 500000; // Correct for minimal speed
349
         if (step_rate >= (8 * 256)) { // higher step rate
293
         if (step_rate >= (8 * 256)) { // higher step rate
350
           uint8_t tmp_step_rate = (step_rate & 0x00FF);
294
           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);
295
+          uint16_t table_address = (uint16_t)&speed_lookuptable_fast[(uint8_t)(step_rate >> 8)][0],
296
+                   gain = (uint16_t)pgm_read_word_near(table_address + 2);
353
           timer = MultiU16X8toH16(tmp_step_rate, gain);
297
           timer = MultiU16X8toH16(tmp_step_rate, gain);
354
           timer = (uint16_t)pgm_read_word_near(table_address) - timer;
298
           timer = (uint16_t)pgm_read_word_near(table_address) - timer;
355
         }
299
         }
356
         else { // lower step rates
300
         else { // lower step rates
357
           uint16_t table_address = (uint16_t)&speed_lookuptable_slow[0][0];
301
           uint16_t table_address = (uint16_t)&speed_lookuptable_slow[0][0];
358
           table_address += ((step_rate) >> 1) & 0xFFFC;
302
           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);
303
+          timer = (uint16_t)pgm_read_word_near(table_address)
304
+                - (((uint16_t)pgm_read_word_near(table_address + 2) * (uint8_t)(step_rate & 0x0007)) >> 3);
361
         }
305
         }
362
         if (timer < 100) { // (20kHz - this should never happen)
306
         if (timer < 100) { // (20kHz - this should never happen)
363
           timer = 100;
307
           timer = 100;

+ 9
- 3
Marlin/src/module/temperature.cpp View File

25
  */
25
  */
26
 
26
 
27
 #include "temperature.h"
27
 #include "temperature.h"
28
+#include "endstops.h"
28
 
29
 
29
 #include "../Marlin.h"
30
 #include "../Marlin.h"
30
 #include "../lcd/ultralcd.h"
31
 #include "../lcd/ultralcd.h"
1725
  *  - Step the babysteps value for each axis towards 0
1726
  *  - Step the babysteps value for each axis towards 0
1726
  *  - For PINS_DEBUGGING, monitor and report endstop pins
1727
  *  - For PINS_DEBUGGING, monitor and report endstop pins
1727
  *  - For ENDSTOP_INTERRUPTS_FEATURE check endstops if flagged
1728
  *  - For ENDSTOP_INTERRUPTS_FEATURE check endstops if flagged
1729
+ *  - Call planner.tick to count down its "ignore" time
1728
  */
1730
  */
1729
 HAL_TEMP_TIMER_ISR {
1731
 HAL_TEMP_TIMER_ISR {
1730
   HAL_timer_isr_prologue(TEMP_TIMER_NUM);
1732
   HAL_timer_isr_prologue(TEMP_TIMER_NUM);
2249
     endstops.run_monitor();  // report changes in endstop status
2251
     endstops.run_monitor();  // report changes in endstop status
2250
   #endif
2252
   #endif
2251
 
2253
 
2254
+  // Update endstops state, if enabled
2252
   #if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
2255
   #if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
2253
-
2254
     extern volatile uint8_t e_hit;
2256
     extern volatile uint8_t e_hit;
2255
-
2256
     if (e_hit && ENDSTOPS_ENABLED) {
2257
     if (e_hit && ENDSTOPS_ENABLED) {
2257
-      endstops.update();  // call endstop update routine
2258
+      endstops.update();
2258
       e_hit--;
2259
       e_hit--;
2259
     }
2260
     }
2261
+  #else
2262
+    if (ENDSTOPS_ENABLED) endstops.update();
2260
   #endif
2263
   #endif
2264
+
2265
+  // Periodically call the planner timer
2266
+  planner.tick();
2261
 }
2267
 }
2262
 
2268
 
2263
 #if HAS_TEMP_SENSOR
2269
 #if HAS_TEMP_SENSOR

+ 1
- 2
Marlin/src/sd/cardreader.cpp View File

29
 #include "../Marlin.h"
29
 #include "../Marlin.h"
30
 #include "../lcd/ultralcd.h"
30
 #include "../lcd/ultralcd.h"
31
 #include "../module/planner.h"
31
 #include "../module/planner.h"
32
-#include "../module/stepper.h"
33
 #include "../module/printcounter.h"
32
 #include "../module/printcounter.h"
34
 #include "../core/language.h"
33
 #include "../core/language.h"
35
 #include "../gcode/queue.h"
34
 #include "../gcode/queue.h"
983
     #endif
982
     #endif
984
 
983
 
985
     #if ENABLED(SD_FINISHED_STEPPERRELEASE) && defined(SD_FINISHED_RELEASECOMMAND)
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
     #endif
986
     #endif
988
     print_job_timer.stop();
987
     print_job_timer.stop();
989
     if (print_job_timer.duration() > 60)
988
     if (print_job_timer.duration() > 60)

Loading…
Cancel
Save