Browse Source

Unify LA for all trapezoid steps

Handle uniformly compression & decompression at any stage of the
trapezoid.

Compared to before, this now enables LA compression also in the cruising
step (handling the converse of a chained wipe), as well as decompression
during acceleration.

Both of these can happen as a result of jerk moves, but are incredibly
rare. This is mostly needed to allow rapid decompression directly at the
acceleration step during travels between a retraction&deretraction.

We also check for the pressure level in a single place, reducing code
size as well as disabling LA earlier when not needed for the rest of the
block.
Yuri D'Elia 4 years ago
parent
commit
ae4abdf11f
2 changed files with 36 additions and 22 deletions
  1. 3 1
      Firmware/planner.cpp
  2. 33 21
      Firmware/stepper.cpp

+ 3 - 1
Firmware/planner.cpp

@@ -1065,10 +1065,12 @@ Having the real displacement of the head, we can calculate the total movement le
      * delta_mm[E_AXIS] >= 0    : Extruding or traveling, but _not_ retracting.
      * |delta_mm[Z_AXIS]| < 0.5 : Z is only moved for leveling (_not_ for priming)
      */
-    block->use_advance_lead = extruder_advance_K
+    block->use_advance_lead = extruder_advance_K > 0
                               && delta_mm[E_AXIS] >= 0
                               && abs(delta_mm[Z_AXIS]) < 0.5;
     if (block->use_advance_lead) {
+        // all extrusion moves with LA require a compression which is proportional to the
+        // extrusion_length to distance ratio (e/D)
         e_D_ratio = (e - position_float[E_AXIS]) /
                     sqrt(sq(x - position_float[X_AXIS])
                          + sq(y - position_float[Y_AXIS])

+ 33 - 21
Firmware/stepper.cpp

@@ -117,8 +117,8 @@ volatile signed char count_direction[NUM_AXIS] = { 1, 1, 1, 1};
   void advance_isr();
 
   static const uint16_t ADV_NEVER      = 0xFFFF;
-  static const uint8_t  ADV_INIT       = 0b01;
-  static const uint8_t  ADV_DECELERATE = 0b10;
+  static const uint8_t  ADV_INIT       = 0b01; // initialize LA
+  static const uint8_t  ADV_ACC_VARY   = 0b10; // varying acceleration phase
 
   static uint16_t nextMainISR;
   static uint16_t nextAdvanceISR;
@@ -130,9 +130,10 @@ volatile signed char count_direction[NUM_AXIS] = { 1, 1, 1, 1};
   static uint16_t current_adv_steps;
   static uint16_t target_adv_steps;
 
-  static int8_t e_steps;
-  static uint8_t e_step_loops;
-  static int8_t LA_phase;
+  static int8_t e_steps;        // scheduled e-steps during each isr loop
+  static uint8_t e_step_loops;  // e-steps to execute at most in each isr loop
+  static uint8_t e_extruding;   // current move is an extrusion move
+  static int8_t LA_phase;       // LA compensation phase
 
   #define _NEXT_ISR(T)    main_Rate = nextMainISR = T
 #else
@@ -366,11 +367,17 @@ FORCE_INLINE void stepper_next_block()
       counter_y.lo = counter_x.lo;
       counter_z.lo = counter_x.lo;
       counter_e.lo = counter_x.lo;
+#ifdef LIN_ADVANCE
+      e_extruding = current_block->steps_e.lo != 0;
+#endif
     } else {
       counter_x.wide = -(current_block->step_event_count.wide >> 1);
       counter_y.wide = counter_x.wide;
       counter_z.wide = counter_x.wide;
       counter_e.wide = counter_x.wide;
+#ifdef LIN_ADVANCE
+      e_extruding = current_block->steps_e.wide != 0;
+#endif
     }
     step_events_completed.wide = 0;
     // Set directions.
@@ -806,7 +813,7 @@ FORCE_INLINE void isr() {
 #ifdef LIN_ADVANCE
         if (current_block->use_advance_lead) {
             if (step_events_completed.wide <= (unsigned long int)step_loops)
-                la_state = ADV_INIT;
+                la_state = ADV_INIT | ADV_ACC_VARY;
         }
 #endif
       }
@@ -825,10 +832,9 @@ FORCE_INLINE void isr() {
 
 #ifdef LIN_ADVANCE
         if (current_block->use_advance_lead) {
-            la_state = ADV_DECELERATE;
             if (step_events_completed.wide <= (unsigned long int)current_block->decelerate_after + step_loops) {
                 target_adv_steps = current_block->final_adv_steps;
-                la_state |= ADV_INIT;
+                la_state = ADV_INIT | ADV_ACC_VARY;
             }
         }
 #endif
@@ -842,17 +848,10 @@ FORCE_INLINE void isr() {
 
 #ifdef LIN_ADVANCE
           if(current_block->use_advance_lead) {
-              if(current_adv_steps < target_adv_steps) {
-                  // after reaching cruising speed, halt compression. if we couldn't accumulate the
-                  // required pressure in the acceleration phase due to lost ticks it's unlikely we
-                  // could undo all of it during deceleration either
-                  target_adv_steps = current_adv_steps;
-              }
-              else if (!nextAdvanceISR && current_adv_steps > target_adv_steps) {
-                  // we're cruising in a block with excess backpressure and without a previous
-                  // acceleration phase - this *cannot* happen during a regular block, but it's
-                  // likely in result of chained a wipe move. release the pressure earlier by
-                  // forcedly enabling LA while cruising!
+              if (!nextAdvanceISR) {
+                  // Due to E-jerk, there can be discontinuities in pressure state where an
+                  // acceleration or deceleration can be skipped or joined with the previous block.
+                  // If LA was not previously active, re-check the pressure level
                   la_state = ADV_INIT;
               }
           }
@@ -865,10 +864,23 @@ FORCE_INLINE void isr() {
 
 #ifdef LIN_ADVANCE
     // avoid multiple instances or function calls to advance_spread
-    if (la_state & ADV_INIT) eISR_Err = current_block->advance_rate / 4;
+    if (la_state & ADV_INIT) {
+        if (current_adv_steps == target_adv_steps) {
+            // nothing to be done in this phase
+            la_state = 0;
+        }
+        else {
+            eISR_Err = current_block->advance_rate / 4;
+            if ((la_state & ADV_ACC_VARY) && e_extruding && (current_adv_steps > target_adv_steps)) {
+                // LA could reverse the direction of extrusion in this phase
+                LA_phase = 0;
+            }
+        }
+    }
     if (la_state & ADV_INIT || nextAdvanceISR != ADV_NEVER) {
+        // update timers & phase for the next iteration
         advance_spread(main_Rate);
-        if (la_state & ADV_DECELERATE) {
+        if (LA_phase >= 0) {
             if (step_loops == e_step_loops)
                 LA_phase = (eISR_Rate > main_Rate);
             else {