|
@@ -104,11 +104,12 @@ Planner planner;
|
104
|
104
|
* A ring buffer of moves described in steps
|
105
|
105
|
*/
|
106
|
106
|
block_t Planner::block_buffer[BLOCK_BUFFER_SIZE];
|
107
|
|
-volatile uint8_t Planner::block_buffer_head, // Index of the next block to be pushed
|
108
|
|
- Planner::block_buffer_tail; // Index of the busy block, if any
|
109
|
|
-uint16_t Planner::cleaning_buffer_counter; // A counter to disable queuing of blocks
|
110
|
|
-uint8_t Planner::delay_before_delivering, // This counter delays delivery of blocks when queue becomes empty to allow the opportunity of merging blocks
|
111
|
|
- Planner::block_buffer_planned; // Index of the optimally planned block
|
|
107
|
+volatile uint8_t Planner::block_buffer_head, // Index of the next block to be pushed
|
|
108
|
+ Planner::block_buffer_nonbusy, // Index of the first non-busy block
|
|
109
|
+ Planner::block_buffer_planned, // Index of the optimally planned block
|
|
110
|
+ Planner::block_buffer_tail; // Index of the busy block, if any
|
|
111
|
+uint16_t Planner::cleaning_buffer_counter; // A counter to disable queuing of blocks
|
|
112
|
+uint8_t Planner::delay_before_delivering; // This counter delays delivery of blocks when queue becomes empty to allow the opportunity of merging blocks
|
112
|
113
|
|
113
|
114
|
uint32_t Planner::max_acceleration_mm_per_s2[XYZE_N], // (mm/s^2) M201 XYZE
|
114
|
115
|
Planner::max_acceleration_steps_per_s2[XYZE_N], // (steps/s^2) Derived from mm_per_s2
|
|
@@ -240,7 +241,6 @@ void Planner::init() {
|
240
|
241
|
bed_level_matrix.set_to_identity();
|
241
|
242
|
#endif
|
242
|
243
|
clear_block_buffer();
|
243
|
|
- block_buffer_planned = 0;
|
244
|
244
|
delay_before_delivering = 0;
|
245
|
245
|
}
|
246
|
246
|
|
|
@@ -703,6 +703,12 @@ void Planner::init() {
|
703
|
703
|
/**
|
704
|
704
|
* Calculate trapezoid parameters, multiplying the entry- and exit-speeds
|
705
|
705
|
* by the provided factors.
|
|
706
|
+ **
|
|
707
|
+ * ############ VERY IMPORTANT ############
|
|
708
|
+ * NOTE that the PRECONDITION to call this function is that the block is
|
|
709
|
+ * NOT BUSY and it is marked as RECALCULATE. That WARRANTIES the Stepper ISR
|
|
710
|
+ * is not and will not use the block while we modify it, so it is safe to
|
|
711
|
+ * alter its values.
|
706
|
712
|
*/
|
707
|
713
|
void Planner::calculate_trapezoid_for_block(block_t* const block, const float &entry_factor, const float &exit_factor) {
|
708
|
714
|
|
|
@@ -744,9 +750,6 @@ void Planner::calculate_trapezoid_for_block(block_t* const block, const float &e
|
744
|
750
|
cruise_rate = block->nominal_rate;
|
745
|
751
|
#endif
|
746
|
752
|
|
747
|
|
- // block->accelerate_until = accelerate_steps;
|
748
|
|
- // block->decelerate_after = accelerate_steps+plateau_steps;
|
749
|
|
-
|
750
|
753
|
#if ENABLED(S_CURVE_ACCELERATION)
|
751
|
754
|
// Jerk controlled speed requires to express speed versus time, NOT steps
|
752
|
755
|
uint32_t acceleration_time = ((float)(cruise_rate - initial_rate) / accel) * (STEPPER_TIMER_RATE),
|
|
@@ -755,32 +758,20 @@ void Planner::calculate_trapezoid_for_block(block_t* const block, const float &e
|
755
|
758
|
// And to offload calculations from the ISR, we also calculate the inverse of those times here
|
756
|
759
|
uint32_t acceleration_time_inverse = get_period_inverse(acceleration_time);
|
757
|
760
|
uint32_t deceleration_time_inverse = get_period_inverse(deceleration_time);
|
758
|
|
-
|
759
|
761
|
#endif
|
760
|
762
|
|
761
|
|
- // Fill variables used by the stepper in a critical section
|
762
|
|
- const bool was_enabled = STEPPER_ISR_ENABLED();
|
763
|
|
- if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
|
764
|
|
-
|
765
|
|
- // Don't update variables if block is busy; it is being interpreted by the planner.
|
766
|
|
- // If this happens, there's a problem... The block speed is inconsistent. Some values
|
767
|
|
- // have already been updated, but the Stepper ISR is already using the block. Fortunately,
|
768
|
|
- // the values being used by the Stepper ISR weren't touched, so just stop here...
|
769
|
|
- // TODO: There may be a way to update a running block, depending on the stepper ISR position.
|
770
|
|
- if (!TEST(block->flag, BLOCK_BIT_BUSY)) {
|
771
|
|
- block->accelerate_until = accelerate_steps;
|
772
|
|
- block->decelerate_after = accelerate_steps + plateau_steps;
|
773
|
|
- block->initial_rate = initial_rate;
|
774
|
|
- #if ENABLED(S_CURVE_ACCELERATION)
|
775
|
|
- block->acceleration_time = acceleration_time;
|
776
|
|
- block->deceleration_time = deceleration_time;
|
777
|
|
- block->acceleration_time_inverse = acceleration_time_inverse;
|
778
|
|
- block->deceleration_time_inverse = deceleration_time_inverse;
|
779
|
|
- block->cruise_rate = cruise_rate;
|
780
|
|
- #endif
|
781
|
|
- block->final_rate = final_rate;
|
782
|
|
- }
|
783
|
|
- if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
|
|
763
|
+ // Store new block parameters
|
|
764
|
+ block->accelerate_until = accelerate_steps;
|
|
765
|
+ block->decelerate_after = accelerate_steps + plateau_steps;
|
|
766
|
+ block->initial_rate = initial_rate;
|
|
767
|
+ #if ENABLED(S_CURVE_ACCELERATION)
|
|
768
|
+ block->acceleration_time = acceleration_time;
|
|
769
|
+ block->deceleration_time = deceleration_time;
|
|
770
|
+ block->acceleration_time_inverse = acceleration_time_inverse;
|
|
771
|
+ block->deceleration_time_inverse = deceleration_time_inverse;
|
|
772
|
+ block->cruise_rate = cruise_rate;
|
|
773
|
+ #endif
|
|
774
|
+ block->final_rate = final_rate;
|
784
|
775
|
}
|
785
|
776
|
|
786
|
777
|
/* PLANNER SPEED DEFINITION
|
|
@@ -831,7 +822,7 @@ void Planner::calculate_trapezoid_for_block(block_t* const block, const float &e
|
831
|
822
|
streaming operating conditions. Use for planning optimizations by avoiding recomputing parts of the
|
832
|
823
|
planner buffer that don't change with the addition of a new block, as describe above. In addition,
|
833
|
824
|
this block can never be less than block_buffer_tail and will always be pushed forward and maintain
|
834
|
|
- this requirement when encountered by the plan_discard_current_block() routine during a cycle.
|
|
825
|
+ this requirement when encountered by the Planner::discard_current_block() routine during a cycle.
|
835
|
826
|
|
836
|
827
|
NOTE: Since the planner only computes on what's in the planner buffer, some motions with lots of short
|
837
|
828
|
line segments, like G2/3 arcs or complex curves, may seem to move slow. This is because there simply isn't
|
|
@@ -875,8 +866,19 @@ void Planner::reverse_pass_kernel(block_t* const current, const block_t * const
|
875
|
866
|
// ISR does not consume the block before being recalculated
|
876
|
867
|
SBI(current->flag, BLOCK_BIT_RECALCULATE);
|
877
|
868
|
|
878
|
|
- // Set the new entry speed
|
879
|
|
- current->entry_speed_sqr = new_entry_speed_sqr;
|
|
869
|
+ // But there is an inherent race condition here, as the block may have
|
|
870
|
+ // become BUSY just before being marked RECALCULATE, so check for that!
|
|
871
|
+ if (stepper.is_block_busy(current)) {
|
|
872
|
+ // Block became busy. Clear the RECALCULATE flag (no point in
|
|
873
|
+ // recalculating BUSY blocks). And don't set its speed, as it can't
|
|
874
|
+ // be updated at this time.
|
|
875
|
+ CBI(current->flag, BLOCK_BIT_RECALCULATE);
|
|
876
|
+ }
|
|
877
|
+ else {
|
|
878
|
+ // Block is not BUSY so this is ahead of the Stepper ISR:
|
|
879
|
+ // Just Set the new entry speed.
|
|
880
|
+ current->entry_speed_sqr = new_entry_speed_sqr;
|
|
881
|
+ }
|
880
|
882
|
}
|
881
|
883
|
}
|
882
|
884
|
}
|
|
@@ -902,12 +904,11 @@ void Planner::reverse_pass() {
|
902
|
904
|
// Reverse Pass: Coarsely maximize all possible deceleration curves back-planning from the last
|
903
|
905
|
// block in buffer. Cease planning when the last optimal planned or tail pointer is reached.
|
904
|
906
|
// NOTE: Forward pass will later refine and correct the reverse pass to create an optimal plan.
|
905
|
|
- block_t *current;
|
906
|
907
|
const block_t *next = NULL;
|
907
|
908
|
while (block_index != planned_block_index) {
|
908
|
909
|
|
909
|
910
|
// Perform the reverse pass
|
910
|
|
- current = &block_buffer[block_index];
|
|
911
|
+ block_t *current = &block_buffer[block_index];
|
911
|
912
|
|
912
|
913
|
// Only consider non sync blocks
|
913
|
914
|
if (!TEST(current->flag, BLOCK_BIT_SYNC_POSITION)) {
|
|
@@ -917,6 +918,18 @@ void Planner::reverse_pass() {
|
917
|
918
|
|
918
|
919
|
// Advance to the next
|
919
|
920
|
block_index = prev_block_index(block_index);
|
|
921
|
+
|
|
922
|
+ // The ISR could advance the block_buffer_planned while we were doing the reverse pass.
|
|
923
|
+ // We must try to avoid using an already consumed block as the last one - So follow
|
|
924
|
+ // changes to the pointer and make sure to limit the loop to the currently busy block
|
|
925
|
+ while (planned_block_index != block_buffer_planned) {
|
|
926
|
+
|
|
927
|
+ // If we reached the busy block or an already processed block, break the loop now
|
|
928
|
+ if (block_index == planned_block_index) return;
|
|
929
|
+
|
|
930
|
+ // Advance the pointer, following the busy block
|
|
931
|
+ planned_block_index = next_block_index(planned_block_index);
|
|
932
|
+ }
|
920
|
933
|
}
|
921
|
934
|
}
|
922
|
935
|
|
|
@@ -940,11 +953,24 @@ void Planner::forward_pass_kernel(const block_t* const previous, block_t* const
|
940
|
953
|
// so the stepper ISR does not consume the block before being recalculated
|
941
|
954
|
SBI(current->flag, BLOCK_BIT_RECALCULATE);
|
942
|
955
|
|
943
|
|
- // Always <= max_entry_speed_sqr. Backward pass sets this.
|
944
|
|
- current->entry_speed_sqr = new_entry_speed_sqr; // Always <= max_entry_speed_sqr. Backward pass sets this.
|
|
956
|
+ // But there is an inherent race condition here, as the block maybe
|
|
957
|
+ // became BUSY, just before it was marked as RECALCULATE, so check
|
|
958
|
+ // if that is the case!
|
|
959
|
+ if (stepper.is_block_busy(current)) {
|
|
960
|
+ // Block became busy. Clear the RECALCULATE flag (no point in
|
|
961
|
+ // recalculating BUSY blocks and don't set its speed, as it can't
|
|
962
|
+ // be updated at this time.
|
|
963
|
+ CBI(current->flag, BLOCK_BIT_RECALCULATE);
|
|
964
|
+ }
|
|
965
|
+ else {
|
|
966
|
+ // Block is not BUSY, we won the race against the Stepper ISR:
|
|
967
|
+
|
|
968
|
+ // Always <= max_entry_speed_sqr. Backward pass sets this.
|
|
969
|
+ current->entry_speed_sqr = new_entry_speed_sqr; // Always <= max_entry_speed_sqr. Backward pass sets this.
|
945
|
970
|
|
946
|
|
- // Set optimal plan pointer.
|
947
|
|
- block_buffer_planned = block_index;
|
|
971
|
+ // Set optimal plan pointer.
|
|
972
|
+ block_buffer_planned = block_index;
|
|
973
|
+ }
|
948
|
974
|
}
|
949
|
975
|
}
|
950
|
976
|
|
|
@@ -981,7 +1007,13 @@ void Planner::forward_pass() {
|
981
|
1007
|
|
982
|
1008
|
// Skip SYNC blocks
|
983
|
1009
|
if (!TEST(current->flag, BLOCK_BIT_SYNC_POSITION)) {
|
984
|
|
- forward_pass_kernel(previous, current, block_index);
|
|
1010
|
+ // If there's no previous block or the previous block is not
|
|
1011
|
+ // BUSY (thus, modifiable) run the forward_pass_kernel. Otherwise,
|
|
1012
|
+ // the previous block became BUSY, so assume the current block's
|
|
1013
|
+ // entry speed can't be altered (since that would also require
|
|
1014
|
+ // updating the exit speed of the previous block).
|
|
1015
|
+ if (!previous || !stepper.is_block_busy(previous))
|
|
1016
|
+ forward_pass_kernel(previous, current, block_index);
|
985
|
1017
|
previous = current;
|
986
|
1018
|
}
|
987
|
1019
|
// Advance to the previous
|
|
@@ -996,16 +1028,15 @@ void Planner::forward_pass() {
|
996
|
1028
|
*/
|
997
|
1029
|
void Planner::recalculate_trapezoids() {
|
998
|
1030
|
// The tail may be changed by the ISR so get a local copy.
|
999
|
|
- uint8_t block_index = block_buffer_tail;
|
1000
|
|
-
|
1001
|
|
- // As there could be a sync block in the head of the queue, and the next loop must not
|
1002
|
|
- // recalculate the head block (as it needs to be specially handled), scan backwards until
|
1003
|
|
- // we find the first non SYNC block
|
1004
|
|
- uint8_t head_block_index = block_buffer_head;
|
|
1031
|
+ uint8_t block_index = block_buffer_tail,
|
|
1032
|
+ head_block_index = block_buffer_head;
|
|
1033
|
+ // Since there could be a sync block in the head of the queue, and the
|
|
1034
|
+ // next loop must not recalculate the head block (as it needs to be
|
|
1035
|
+ // specially handled), scan backwards to the first non-SYNC block.
|
1005
|
1036
|
while (head_block_index != block_index) {
|
1006
|
1037
|
|
1007
|
1038
|
// Go back (head always point to the first free block)
|
1008
|
|
- uint8_t prev_index = prev_block_index(head_block_index);
|
|
1039
|
+ const uint8_t prev_index = prev_block_index(head_block_index);
|
1009
|
1040
|
|
1010
|
1041
|
// Get the pointer to the block
|
1011
|
1042
|
block_t *prev = &block_buffer[prev_index];
|
|
@@ -1015,7 +1046,7 @@ void Planner::recalculate_trapezoids() {
|
1015
|
1046
|
|
1016
|
1047
|
// Examine the previous block. This and all following are SYNC blocks
|
1017
|
1048
|
head_block_index = prev_index;
|
1018
|
|
- };
|
|
1049
|
+ }
|
1019
|
1050
|
|
1020
|
1051
|
// Go from the tail (currently executed block) to the first block, without including it)
|
1021
|
1052
|
block_t *current = NULL, *next = NULL;
|
|
@@ -1037,17 +1068,24 @@ void Planner::recalculate_trapezoids() {
|
1037
|
1068
|
// RECALCULATE yet, but the next one is. That's the reason for the following line.
|
1038
|
1069
|
SBI(current->flag, BLOCK_BIT_RECALCULATE);
|
1039
|
1070
|
|
1040
|
|
- // NOTE: Entry and exit factors always > 0 by all previous logic operations.
|
1041
|
|
- const float current_nominal_speed = SQRT(current->nominal_speed_sqr),
|
1042
|
|
- nomr = 1.0 / current_nominal_speed;
|
1043
|
|
- calculate_trapezoid_for_block(current, current_entry_speed * nomr, next_entry_speed * nomr);
|
1044
|
|
- #if ENABLED(LIN_ADVANCE)
|
1045
|
|
- if (current->use_advance_lead) {
|
1046
|
|
- const float comp = current->e_D_ratio * extruder_advance_K * axis_steps_per_mm[E_AXIS];
|
1047
|
|
- current->max_adv_steps = current_nominal_speed * comp;
|
1048
|
|
- current->final_adv_steps = next_entry_speed * comp;
|
1049
|
|
- }
|
1050
|
|
- #endif
|
|
1071
|
+ // But there is an inherent race condition here, as the block maybe
|
|
1072
|
+ // became BUSY, just before it was marked as RECALCULATE, so check
|
|
1073
|
+ // if that is the case!
|
|
1074
|
+ if (!stepper.is_block_busy(current)) {
|
|
1075
|
+ // Block is not BUSY, we won the race against the Stepper ISR:
|
|
1076
|
+
|
|
1077
|
+ // NOTE: Entry and exit factors always > 0 by all previous logic operations.
|
|
1078
|
+ const float current_nominal_speed = SQRT(current->nominal_speed_sqr),
|
|
1079
|
+ nomr = 1.0 / current_nominal_speed;
|
|
1080
|
+ calculate_trapezoid_for_block(current, current_entry_speed * nomr, next_entry_speed * nomr);
|
|
1081
|
+ #if ENABLED(LIN_ADVANCE)
|
|
1082
|
+ if (current->use_advance_lead) {
|
|
1083
|
+ const float comp = current->e_D_ratio * extruder_advance_K * axis_steps_per_mm[E_AXIS];
|
|
1084
|
+ current->max_adv_steps = current_nominal_speed * comp;
|
|
1085
|
+ current->final_adv_steps = next_entry_speed * comp;
|
|
1086
|
+ }
|
|
1087
|
+ #endif
|
|
1088
|
+ }
|
1051
|
1089
|
|
1052
|
1090
|
// Reset current only to ensure next trapezoid is computed - The
|
1053
|
1091
|
// stepper is free to use the block from now on.
|
|
@@ -1070,16 +1108,23 @@ void Planner::recalculate_trapezoids() {
|
1070
|
1108
|
// marked as RECALCULATE yet. That's the reason for the following line.
|
1071
|
1109
|
SBI(next->flag, BLOCK_BIT_RECALCULATE);
|
1072
|
1110
|
|
1073
|
|
- const float next_nominal_speed = SQRT(next->nominal_speed_sqr),
|
1074
|
|
- nomr = 1.0 / next_nominal_speed;
|
1075
|
|
- calculate_trapezoid_for_block(next, next_entry_speed * nomr, (MINIMUM_PLANNER_SPEED) * nomr);
|
1076
|
|
- #if ENABLED(LIN_ADVANCE)
|
1077
|
|
- if (next->use_advance_lead) {
|
1078
|
|
- const float comp = next->e_D_ratio * extruder_advance_K * axis_steps_per_mm[E_AXIS];
|
1079
|
|
- next->max_adv_steps = next_nominal_speed * comp;
|
1080
|
|
- next->final_adv_steps = (MINIMUM_PLANNER_SPEED) * comp;
|
1081
|
|
- }
|
1082
|
|
- #endif
|
|
1111
|
+ // But there is an inherent race condition here, as the block maybe
|
|
1112
|
+ // became BUSY, just before it was marked as RECALCULATE, so check
|
|
1113
|
+ // if that is the case!
|
|
1114
|
+ if (!stepper.is_block_busy(current)) {
|
|
1115
|
+ // Block is not BUSY, we won the race against the Stepper ISR:
|
|
1116
|
+
|
|
1117
|
+ const float next_nominal_speed = SQRT(next->nominal_speed_sqr),
|
|
1118
|
+ nomr = 1.0 / next_nominal_speed;
|
|
1119
|
+ calculate_trapezoid_for_block(next, next_entry_speed * nomr, (MINIMUM_PLANNER_SPEED) * nomr);
|
|
1120
|
+ #if ENABLED(LIN_ADVANCE)
|
|
1121
|
+ if (next->use_advance_lead) {
|
|
1122
|
+ const float comp = next->e_D_ratio * extruder_advance_K * axis_steps_per_mm[E_AXIS];
|
|
1123
|
+ next->max_adv_steps = next_nominal_speed * comp;
|
|
1124
|
+ next->final_adv_steps = (MINIMUM_PLANNER_SPEED) * comp;
|
|
1125
|
+ }
|
|
1126
|
+ #endif
|
|
1127
|
+ }
|
1083
|
1128
|
|
1084
|
1129
|
// Reset next only to ensure its trapezoid is computed - The stepper is free to use
|
1085
|
1130
|
// the block from now on.
|
|
@@ -1423,7 +1468,7 @@ void Planner::quick_stop() {
|
1423
|
1468
|
if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
|
1424
|
1469
|
|
1425
|
1470
|
// Drop all queue entries
|
1426
|
|
- block_buffer_planned = block_buffer_head = block_buffer_tail;
|
|
1471
|
+ block_buffer_nonbusy = block_buffer_planned = block_buffer_head = block_buffer_tail;
|
1427
|
1472
|
|
1428
|
1473
|
// Restart the block delay for the first movement - As the queue was
|
1429
|
1474
|
// forced to empty, there's no risk the ISR will touch this.
|
|
@@ -1906,7 +1951,8 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
|
1906
|
1951
|
// Example: At 120mm/s a 60mm move takes 0.5s. So this will give 2.0.
|
1907
|
1952
|
float inverse_secs = fr_mm_s * inverse_millimeters;
|
1908
|
1953
|
|
1909
|
|
- const uint8_t moves_queued = movesplanned();
|
|
1954
|
+ // Get the number of non busy movements in queue (non busy means that they can be altered)
|
|
1955
|
+ const uint8_t moves_queued = nonbusy_movesplanned();
|
1910
|
1956
|
|
1911
|
1957
|
// Slow down when the buffer starts to empty, rather than wait at the corner for a buffer refill
|
1912
|
1958
|
#if ENABLED(SLOWDOWN) || ENABLED(ULTRA_LCD) || defined(XY_FREQUENCY_LIMIT)
|