Browse Source

[2.0.x] Fix stepper/planner race condition and Stepper pulse timer (#11081)

* Planner: Removal of some race conditions between Stepper ISR and Planner, some of them pointed out by @AnHardt, some of my own findings
* Fixing timing on stepper pulses adding a compensation for the non-null time required to set ports.
Eduardo José Tagle 7 years ago
parent
commit
48a15d1c7e
2 changed files with 71 additions and 21 deletions
  1. 33
    7
      Marlin/src/module/planner.cpp
  2. 38
    14
      Marlin/src/module/stepper.h

+ 33
- 7
Marlin/src/module/planner.cpp View File

@@ -758,7 +758,11 @@ void Planner::calculate_trapezoid_for_block(block_t* const block, const float &e
758 758
   const bool was_enabled = STEPPER_ISR_ENABLED();
759 759
   if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
760 760
 
761
-  // Don't update variables if block is busy: It is being interpreted by the planner
761
+  // Don't update variables if block is busy; it is being interpreted by the planner.
762
+  // If this happens, there's a problem... The block speed is inconsistent. Some values
763
+  // have already been updated, but the Stepper ISR is already using the block. Fortunately,
764
+  // the values being used by the Stepper ISR weren't touched, so just stop here...
765
+  // TODO: There may be a way to update a running block, depending on the stepper ISR position.
762 766
   if (!TEST(block->flag, BLOCK_BIT_BUSY)) {
763 767
     block->accelerate_until = accelerate_steps;
764 768
     block->decelerate_after = accelerate_steps + plateau_steps;
@@ -862,10 +866,13 @@ void Planner::reverse_pass_kernel(block_t* const current, const block_t * const
862 866
         ? max_entry_speed_sqr
863 867
         : MIN(max_entry_speed_sqr, max_allowable_speed_sqr(-current->acceleration, next ? next->entry_speed_sqr : sq(MINIMUM_PLANNER_SPEED), current->millimeters));
864 868
       if (current->entry_speed_sqr != new_entry_speed_sqr) {
865
-        current->entry_speed_sqr = new_entry_speed_sqr;
866 869
 
867
-        // Need to recalculate the block speed
870
+        // Need to recalculate the block speed - Mark it now, so the stepper
871
+        // ISR does not consume the block before being recalculated
868 872
         SBI(current->flag, BLOCK_BIT_RECALCULATE);
873
+
874
+        // Set the new entry speed
875
+        current->entry_speed_sqr = new_entry_speed_sqr;
869 876
       }
870 877
     }
871 878
   }
@@ -925,14 +932,15 @@ void Planner::forward_pass_kernel(const block_t* const previous, block_t* const
925 932
       // If true, current block is full-acceleration and we can move the planned pointer forward.
926 933
       if (new_entry_speed_sqr < current->entry_speed_sqr) {
927 934
 
935
+        // Mark we need to recompute the trapezoidal shape, and do it now,
936
+        // so the stepper ISR does not consume the block before being recalculated
937
+        SBI(current->flag, BLOCK_BIT_RECALCULATE);
938
+
928 939
         // Always <= max_entry_speed_sqr. Backward pass sets this.
929 940
         current->entry_speed_sqr = new_entry_speed_sqr; // Always <= max_entry_speed_sqr. Backward pass sets this.
930 941
 
931 942
         // Set optimal plan pointer.
932 943
         block_buffer_planned = block_index;
933
-
934
-        // And mark we need to recompute the trapezoidal shape
935
-        SBI(current->flag, BLOCK_BIT_RECALCULATE);
936 944
       }
937 945
     }
938 946
 
@@ -1019,6 +1027,12 @@ void Planner::recalculate_trapezoids() {
1019 1027
       if (current) {
1020 1028
         // Recalculate if current block entry or exit junction speed has changed.
1021 1029
         if (TEST(current->flag, BLOCK_BIT_RECALCULATE) || TEST(next->flag, BLOCK_BIT_RECALCULATE)) {
1030
+
1031
+          // Mark the current block as RECALCULATE, to protect it from the Stepper ISR running it.
1032
+          // Note that due to the above condition, there's a chance the current block isn't marked as
1033
+          // RECALCULATE yet, but the next one is. That's the reason for the following line.
1034
+          SBI(current->flag, BLOCK_BIT_RECALCULATE);
1035
+
1022 1036
           // NOTE: Entry and exit factors always > 0 by all previous logic operations.
1023 1037
           const float current_nominal_speed = SQRT(current->nominal_speed_sqr),
1024 1038
                       nomr = 1.0 / current_nominal_speed;
@@ -1030,7 +1044,10 @@ void Planner::recalculate_trapezoids() {
1030 1044
               current->final_adv_steps = next_entry_speed * comp;
1031 1045
             }
1032 1046
           #endif
1033
-          CBI(current->flag, BLOCK_BIT_RECALCULATE); // Reset current only to ensure next trapezoid is computed
1047
+
1048
+          // Reset current only to ensure next trapezoid is computed - The
1049
+          // stepper is free to use the block from now on.
1050
+          CBI(current->flag, BLOCK_BIT_RECALCULATE);
1034 1051
         }
1035 1052
       }
1036 1053
 
@@ -1043,6 +1060,12 @@ void Planner::recalculate_trapezoids() {
1043 1060
 
1044 1061
   // Last/newest block in buffer. Exit speed is set with MINIMUM_PLANNER_SPEED. Always recalculated.
1045 1062
   if (next) {
1063
+
1064
+    // Mark the next(last) block as RECALCULATE, to prevent the Stepper ISR running it.
1065
+    // As the last block is always recalculated here, there is a chance the block isn't
1066
+    // marked as RECALCULATE yet. That's the reason for the following line.
1067
+    SBI(next->flag, BLOCK_BIT_RECALCULATE);
1068
+
1046 1069
     const float next_nominal_speed = SQRT(next->nominal_speed_sqr),
1047 1070
                 nomr = 1.0 / next_nominal_speed;
1048 1071
     calculate_trapezoid_for_block(next, next_entry_speed * nomr, (MINIMUM_PLANNER_SPEED) * nomr);
@@ -1053,6 +1076,9 @@ void Planner::recalculate_trapezoids() {
1053 1076
         next->final_adv_steps = (MINIMUM_PLANNER_SPEED) * comp;
1054 1077
       }
1055 1078
     #endif
1079
+
1080
+    // Reset next only to ensure its trapezoid is computed - The stepper is free to use
1081
+    // the block from now on.
1056 1082
     CBI(next->flag, BLOCK_BIT_RECALCULATE);
1057 1083
   }
1058 1084
 }

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

@@ -53,7 +53,7 @@
53 53
 //
54 54
 
55 55
 #ifndef MINIMUM_STEPPER_PULSE
56
-  #define MINIMUM_STEPPER_PULSE 0
56
+  #define MINIMUM_STEPPER_PULSE 0UL
57 57
 #endif
58 58
 
59 59
 #ifndef MAXIMUM_STEPPER_RATE
@@ -86,7 +86,10 @@
86 86
   // Stepper Loop base cycles
87 87
   #define ISR_LOOP_BASE_CYCLES 4UL
88 88
 
89
-  // And each stepper takes 16 cycles
89
+  // To start the step pulse, in the worst case takes
90
+  #define ISR_START_STEPPER_CYCLES 13UL
91
+
92
+  // And each stepper (start + stop pulse) takes in worst case
90 93
   #define ISR_STEPPER_CYCLES 16UL
91 94
 
92 95
 #else
@@ -111,51 +114,72 @@
111 114
   // Stepper Loop base cycles
112 115
   #define ISR_LOOP_BASE_CYCLES 32UL
113 116
 
114
-  // And each stepper takes 88 cycles
117
+  // To start the step pulse, in the worst case takes
118
+  #define ISR_START_STEPPER_CYCLES 57UL
119
+
120
+  // And each stepper (start + stop pulse) takes in worst case
115 121
   #define ISR_STEPPER_CYCLES 88UL
116 122
 
117 123
 #endif
118 124
 
119 125
 // Add time for each stepper
120 126
 #ifdef HAS_X_STEP
121
-  #define ISR_X_STEPPER_CYCLES ISR_STEPPER_CYCLES
127
+  #define ISR_START_X_STEPPER_CYCLES ISR_START_STEPPER_CYCLES
128
+  #define ISR_X_STEPPER_CYCLES       ISR_STEPPER_CYCLES
122 129
 #else
123
-  #define ISR_X_STEPPER_CYCLES 0UL
130
+  #define ISR_START_X_STEPPER_CYCLES 0UL
131
+  #define ISR_X_STEPPER_CYCLES       0UL
124 132
 #endif
125 133
 #ifdef HAS_Y_STEP
126
-  #define ISR_Y_STEPPER_CYCLES ISR_STEPPER_CYCLES
134
+  #define ISR_START_Y_STEPPER_CYCLES ISR_START_STEPPER_CYCLES
135
+  #define ISR_Y_STEPPER_CYCLES       ISR_STEPPER_CYCLES
127 136
 #else
128
-  #define ISR_Y_STEPPER_CYCLES 0UL
137
+  #define ISR_START_Y_STEPPER_CYCLES 0UL
138
+  #define ISR_Y_STEPPER_CYCLES       0UL
129 139
 #endif
130 140
 #ifdef HAS_Z_STEP
131
-  #define ISR_Z_STEPPER_CYCLES ISR_STEPPER_CYCLES
141
+  #define ISR_START_Z_STEPPER_CYCLES ISR_START_STEPPER_CYCLES
142
+  #define ISR_Z_STEPPER_CYCLES       ISR_STEPPER_CYCLES
132 143
 #else
133
-  #define ISR_Z_STEPPER_CYCLES 0UL
144
+  #define ISR_START_Z_STEPPER_CYCLES 0UL
145
+  #define ISR_Z_STEPPER_CYCLES       0UL
134 146
 #endif
135 147
 
136 148
 // E is always interpolated, even for mixing extruders
137
-#define ISR_E_STEPPER_CYCLES ISR_STEPPER_CYCLES
149
+#define ISR_START_E_STEPPER_CYCLES   ISR_START_STEPPER_CYCLES
150
+#define ISR_E_STEPPER_CYCLES         ISR_STEPPER_CYCLES
138 151
 
139 152
 // If linear advance is disabled, then the loop also handles them
140 153
 #if DISABLED(LIN_ADVANCE) && ENABLED(MIXING_EXTRUDER)
154
+  #define ISR_START_MIXING_STEPPER_CYCLES ((MIXING_STEPPERS) * (ISR_START_STEPPER_CYCLES))
141 155
   #define ISR_MIXING_STEPPER_CYCLES ((MIXING_STEPPERS) * (ISR_STEPPER_CYCLES))
142 156
 #else
157
+  #define ISR_START_MIXING_STEPPER_CYCLES 0UL
143 158
   #define ISR_MIXING_STEPPER_CYCLES  0UL
144 159
 #endif
145 160
 
161
+// Calculate the minimum time to start all stepper pulses in the ISR loop
162
+#define MIN_ISR_START_LOOP_CYCLES (ISR_START_X_STEPPER_CYCLES + ISR_START_Y_STEPPER_CYCLES + ISR_START_Z_STEPPER_CYCLES + ISR_START_E_STEPPER_CYCLES + ISR_START_MIXING_STEPPER_CYCLES)
163
+
146 164
 // And the total minimum loop time, not including the base
147 165
 #define MIN_ISR_LOOP_CYCLES (ISR_X_STEPPER_CYCLES + ISR_Y_STEPPER_CYCLES + ISR_Z_STEPPER_CYCLES + ISR_E_STEPPER_CYCLES + ISR_MIXING_STEPPER_CYCLES)
148 166
 
149 167
 // Calculate the minimum MPU cycles needed per pulse to enforce, limited to the max stepper rate
150 168
 #define _MIN_STEPPER_PULSE_CYCLES(N) MAX((F_CPU) / (MAXIMUM_STEPPER_RATE), ((F_CPU) / 500000UL) * (N))
151 169
 #if MINIMUM_STEPPER_PULSE
152
-  #define MIN_STEPPER_PULSE_CYCLES _MIN_STEPPER_PULSE_CYCLES(MINIMUM_STEPPER_PULSE)
170
+  #define MIN_STEPPER_PULSE_CYCLES _MIN_STEPPER_PULSE_CYCLES((MINIMUM_STEPPER_PULSE))
153 171
 #else
154
-  #define MIN_STEPPER_PULSE_CYCLES _MIN_STEPPER_PULSE_CYCLES(1)
172
+  #define MIN_STEPPER_PULSE_CYCLES _MIN_STEPPER_PULSE_CYCLES(1UL)
155 173
 #endif
156 174
 
157
-#define MIN_PULSE_TICKS  ((PULSE_TIMER_TICKS_PER_US) * (MINIMUM_STEPPER_PULSE))
158
-#define ADDED_STEP_TICKS ((MIN_STEPPER_PULSE_CYCLES) / (PULSE_TIMER_PRESCALE) - MIN_PULSE_TICKS)
175
+// Calculate the minimum ticks of the PULSE timer that must elapse with the step pulse enabled
176
+// adding the "start stepper pulse" code section execution cycles to account for that not all
177
+// pulses start at the beginning of the loop, so an extra time must be added to compensate so
178
+// the last generated pulse (usually the extruder stepper) has the right length
179
+#define MIN_PULSE_TICKS (((PULSE_TIMER_TICKS_PER_US) * (MINIMUM_STEPPER_PULSE)) + ((MIN_ISR_START_LOOP_CYCLES) / (PULSE_TIMER_PRESCALE)))
180
+
181
+// Calculate the extra ticks of the PULSE timer between step pulses
182
+#define ADDED_STEP_TICKS (((MIN_STEPPER_PULSE_CYCLES) / (PULSE_TIMER_PRESCALE)) - (MIN_PULSE_TICKS))
159 183
 
160 184
 // But the user could be enforcing a minimum time, so the loop time is
161 185
 #define ISR_LOOP_CYCLES (ISR_LOOP_BASE_CYCLES + MAX(MIN_STEPPER_PULSE_CYCLES, MIN_ISR_LOOP_CYCLES))

Loading…
Cancel
Save