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
   const bool was_enabled = STEPPER_ISR_ENABLED();
758
   const bool was_enabled = STEPPER_ISR_ENABLED();
759
   if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
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
   if (!TEST(block->flag, BLOCK_BIT_BUSY)) {
766
   if (!TEST(block->flag, BLOCK_BIT_BUSY)) {
763
     block->accelerate_until = accelerate_steps;
767
     block->accelerate_until = accelerate_steps;
764
     block->decelerate_after = accelerate_steps + plateau_steps;
768
     block->decelerate_after = accelerate_steps + plateau_steps;
862
         ? max_entry_speed_sqr
866
         ? max_entry_speed_sqr
863
         : MIN(max_entry_speed_sqr, max_allowable_speed_sqr(-current->acceleration, next ? next->entry_speed_sqr : sq(MINIMUM_PLANNER_SPEED), current->millimeters));
867
         : MIN(max_entry_speed_sqr, max_allowable_speed_sqr(-current->acceleration, next ? next->entry_speed_sqr : sq(MINIMUM_PLANNER_SPEED), current->millimeters));
864
       if (current->entry_speed_sqr != new_entry_speed_sqr) {
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
         SBI(current->flag, BLOCK_BIT_RECALCULATE);
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
       // If true, current block is full-acceleration and we can move the planned pointer forward.
932
       // If true, current block is full-acceleration and we can move the planned pointer forward.
926
       if (new_entry_speed_sqr < current->entry_speed_sqr) {
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
         // Always <= max_entry_speed_sqr. Backward pass sets this.
939
         // Always <= max_entry_speed_sqr. Backward pass sets this.
929
         current->entry_speed_sqr = new_entry_speed_sqr; // Always <= max_entry_speed_sqr. Backward pass sets this.
940
         current->entry_speed_sqr = new_entry_speed_sqr; // Always <= max_entry_speed_sqr. Backward pass sets this.
930
 
941
 
931
         // Set optimal plan pointer.
942
         // Set optimal plan pointer.
932
         block_buffer_planned = block_index;
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
       if (current) {
1027
       if (current) {
1020
         // Recalculate if current block entry or exit junction speed has changed.
1028
         // Recalculate if current block entry or exit junction speed has changed.
1021
         if (TEST(current->flag, BLOCK_BIT_RECALCULATE) || TEST(next->flag, BLOCK_BIT_RECALCULATE)) {
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
           // NOTE: Entry and exit factors always > 0 by all previous logic operations.
1036
           // NOTE: Entry and exit factors always > 0 by all previous logic operations.
1023
           const float current_nominal_speed = SQRT(current->nominal_speed_sqr),
1037
           const float current_nominal_speed = SQRT(current->nominal_speed_sqr),
1024
                       nomr = 1.0 / current_nominal_speed;
1038
                       nomr = 1.0 / current_nominal_speed;
1030
               current->final_adv_steps = next_entry_speed * comp;
1044
               current->final_adv_steps = next_entry_speed * comp;
1031
             }
1045
             }
1032
           #endif
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
 
1060
 
1044
   // Last/newest block in buffer. Exit speed is set with MINIMUM_PLANNER_SPEED. Always recalculated.
1061
   // Last/newest block in buffer. Exit speed is set with MINIMUM_PLANNER_SPEED. Always recalculated.
1045
   if (next) {
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
     const float next_nominal_speed = SQRT(next->nominal_speed_sqr),
1069
     const float next_nominal_speed = SQRT(next->nominal_speed_sqr),
1047
                 nomr = 1.0 / next_nominal_speed;
1070
                 nomr = 1.0 / next_nominal_speed;
1048
     calculate_trapezoid_for_block(next, next_entry_speed * nomr, (MINIMUM_PLANNER_SPEED) * nomr);
1071
     calculate_trapezoid_for_block(next, next_entry_speed * nomr, (MINIMUM_PLANNER_SPEED) * nomr);
1053
         next->final_adv_steps = (MINIMUM_PLANNER_SPEED) * comp;
1076
         next->final_adv_steps = (MINIMUM_PLANNER_SPEED) * comp;
1054
       }
1077
       }
1055
     #endif
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
     CBI(next->flag, BLOCK_BIT_RECALCULATE);
1082
     CBI(next->flag, BLOCK_BIT_RECALCULATE);
1057
   }
1083
   }
1058
 }
1084
 }

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

53
 //
53
 //
54
 
54
 
55
 #ifndef MINIMUM_STEPPER_PULSE
55
 #ifndef MINIMUM_STEPPER_PULSE
56
-  #define MINIMUM_STEPPER_PULSE 0
56
+  #define MINIMUM_STEPPER_PULSE 0UL
57
 #endif
57
 #endif
58
 
58
 
59
 #ifndef MAXIMUM_STEPPER_RATE
59
 #ifndef MAXIMUM_STEPPER_RATE
86
   // Stepper Loop base cycles
86
   // Stepper Loop base cycles
87
   #define ISR_LOOP_BASE_CYCLES 4UL
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
   #define ISR_STEPPER_CYCLES 16UL
93
   #define ISR_STEPPER_CYCLES 16UL
91
 
94
 
92
 #else
95
 #else
111
   // Stepper Loop base cycles
114
   // Stepper Loop base cycles
112
   #define ISR_LOOP_BASE_CYCLES 32UL
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
   #define ISR_STEPPER_CYCLES 88UL
121
   #define ISR_STEPPER_CYCLES 88UL
116
 
122
 
117
 #endif
123
 #endif
118
 
124
 
119
 // Add time for each stepper
125
 // Add time for each stepper
120
 #ifdef HAS_X_STEP
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
 #else
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
 #endif
132
 #endif
125
 #ifdef HAS_Y_STEP
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
 #else
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
 #endif
139
 #endif
130
 #ifdef HAS_Z_STEP
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
 #else
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
 #endif
146
 #endif
135
 
147
 
136
 // E is always interpolated, even for mixing extruders
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
 // If linear advance is disabled, then the loop also handles them
152
 // If linear advance is disabled, then the loop also handles them
140
 #if DISABLED(LIN_ADVANCE) && ENABLED(MIXING_EXTRUDER)
153
 #if DISABLED(LIN_ADVANCE) && ENABLED(MIXING_EXTRUDER)
154
+  #define ISR_START_MIXING_STEPPER_CYCLES ((MIXING_STEPPERS) * (ISR_START_STEPPER_CYCLES))
141
   #define ISR_MIXING_STEPPER_CYCLES ((MIXING_STEPPERS) * (ISR_STEPPER_CYCLES))
155
   #define ISR_MIXING_STEPPER_CYCLES ((MIXING_STEPPERS) * (ISR_STEPPER_CYCLES))
142
 #else
156
 #else
157
+  #define ISR_START_MIXING_STEPPER_CYCLES 0UL
143
   #define ISR_MIXING_STEPPER_CYCLES  0UL
158
   #define ISR_MIXING_STEPPER_CYCLES  0UL
144
 #endif
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
 // And the total minimum loop time, not including the base
164
 // And the total minimum loop time, not including the base
147
 #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)
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
 // Calculate the minimum MPU cycles needed per pulse to enforce, limited to the max stepper rate
167
 // Calculate the minimum MPU cycles needed per pulse to enforce, limited to the max stepper rate
150
 #define _MIN_STEPPER_PULSE_CYCLES(N) MAX((F_CPU) / (MAXIMUM_STEPPER_RATE), ((F_CPU) / 500000UL) * (N))
168
 #define _MIN_STEPPER_PULSE_CYCLES(N) MAX((F_CPU) / (MAXIMUM_STEPPER_RATE), ((F_CPU) / 500000UL) * (N))
151
 #if MINIMUM_STEPPER_PULSE
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
 #else
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
 #endif
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
 // But the user could be enforcing a minimum time, so the loop time is
184
 // But the user could be enforcing a minimum time, so the loop time is
161
 #define ISR_LOOP_CYCLES (ISR_LOOP_BASE_CYCLES + MAX(MIN_STEPPER_PULSE_CYCLES, MIN_ISR_LOOP_CYCLES))
185
 #define ISR_LOOP_CYCLES (ISR_LOOP_BASE_CYCLES + MAX(MIN_STEPPER_PULSE_CYCLES, MIN_ISR_LOOP_CYCLES))

Loading…
Cancel
Save