Browse Source

Merge pull request #2591 from wavexx/la15_chained_wipes

Fix chained wipes in Linear Advance 1.5
DRracer 4 years ago
parent
commit
7c1bf6a836
3 changed files with 64 additions and 35 deletions
  1. 0 1
      Firmware/Marlin_main.cpp
  2. 15 10
      Firmware/planner.cpp
  3. 49 24
      Firmware/stepper.cpp

+ 0 - 1
Firmware/Marlin_main.cpp

@@ -7116,7 +7116,6 @@ Sigma_Exit:
       {
           float e = code_value();
 #ifndef LA_NOCOMPAT
-
           e = la10c_jerk(e);
 #endif
           cs.max_jerk[E_AXIS] = e;

+ 15 - 10
Firmware/planner.cpp

@@ -1061,16 +1061,16 @@ Having the real displacement of the head, we can calculate the total movement le
     /**
      * Use LIN_ADVANCE within this block if all these are true:
      *
-     * block->steps_e           : This is a print move, because we checked for X, Y, Z steps before.
      * extruder_advance_K       : There is an advance factor set.
-     * delta_mm[E_AXIS] > 0     : Extruder is running forward (e.g., for "Wipe while retracting" (Slic3r) or "Combing" (Cura) moves)
+     * 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 = block->steps_e.wide
-                              && extruder_advance_K
-                              && delta_mm[E_AXIS] > 0
+    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])
@@ -1082,10 +1082,10 @@ Having the real displacement of the head, we can calculate the total movement le
         // 100mm wide lines using 3mm filament or 35mm wide lines using 1.75mm filament.
         if (e_D_ratio > 3.0)
             block->use_advance_lead = false;
-        else {
-            const uint32_t max_accel_steps_per_s2 = cs.max_jerk[E_AXIS] / (extruder_advance_K * e_D_ratio) * steps_per_mm;
-            if (block->acceleration_st > max_accel_steps_per_s2) {
-                block->acceleration_st = max_accel_steps_per_s2;
+        else if (e_D_ratio > 0) {
+            const float max_accel_per_s2 = cs.max_jerk[E_AXIS] / (extruder_advance_K * e_D_ratio);
+            if (cs.acceleration > max_accel_per_s2) {
+                block->acceleration_st = ceil(max_accel_per_s2 * steps_per_mm);
                 #ifdef LA_DEBUG
                 SERIAL_ECHOLNPGM("LA: Block acceleration limited due to max E-jerk");
                 #endif
@@ -1133,9 +1133,14 @@ Having the real displacement of the head, we can calculate the total movement le
       block->adv_comp = extruder_advance_K * e_D_ratio * cs.axis_steps_per_unit[E_AXIS];
       block->max_adv_steps = block->nominal_speed * block->adv_comp;
 
+      float advance_speed;
+      if (e_D_ratio > 0)
+          advance_speed = (extruder_advance_K * e_D_ratio * block->acceleration * cs.axis_steps_per_unit[E_AXIS]);
+      else
+          advance_speed = cs.max_jerk[E_AXIS] * cs.axis_steps_per_unit[E_AXIS];
+
       // to save more space we avoid another copy of calc_timer and go through slow division, but we
       // still need to replicate the *exact* same step grouping policy (see below)
-      float advance_speed = (extruder_advance_K * e_D_ratio * block->acceleration * cs.axis_steps_per_unit[E_AXIS]);
       if (advance_speed > MAX_STEP_FREQUENCY) advance_speed = MAX_STEP_FREQUENCY;
       float advance_rate = (F_CPU / 8.0) / advance_speed;
       if (advance_speed > 20000) {

+ 49 - 24
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;
@@ -128,13 +128,12 @@ volatile signed char count_direction[NUM_AXIS] = { 1, 1, 1, 1};
   static uint16_t eISR_Err;
 
   static uint16_t current_adv_steps;
-  static uint16_t final_adv_steps;
-  static uint16_t max_adv_steps;
-  static uint32_t LA_decelerate_after;
+  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
@@ -349,15 +348,12 @@ FORCE_INLINE void stepper_next_block()
 
 #ifdef LIN_ADVANCE
     if (current_block->use_advance_lead) {
-        LA_decelerate_after = current_block->decelerate_after;
-        final_adv_steps = current_block->final_adv_steps;
-        max_adv_steps = current_block->max_adv_steps;
         e_step_loops = current_block->advance_step_loops;
+        target_adv_steps = current_block->max_adv_steps;
     } else {
-        e_steps = 0;
         e_step_loops = 1;
-        current_adv_steps = 0;
     }
+    e_steps = 0;
     nextAdvanceISR = ADV_NEVER;
     LA_phase = -1;
 #endif
@@ -371,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.
@@ -811,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
       }
@@ -827,11 +829,13 @@ FORCE_INLINE void isr() {
         uint16_t timer = calc_timer(step_rate, step_loops);
         _NEXT_ISR(timer);
         deceleration_time += timer;
+
 #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)
-                la_state |= ADV_INIT;
+            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 | ADV_ACC_VARY;
+            }
         }
 #endif
       }
@@ -841,6 +845,17 @@ FORCE_INLINE void isr() {
           // the initial interrupt blocking.
           OCR1A_nominal = calc_timer(uint16_t(current_block->nominal_rate), step_loops);
           step_loops_nominal = step_loops;
+
+#ifdef LIN_ADVANCE
+          if(current_block->use_advance_lead) {
+              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;
+              }
+          }
+#endif
         }
         _NEXT_ISR(OCR1A_nominal);
       }
@@ -849,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 {
@@ -898,7 +926,7 @@ FORCE_INLINE void isr() {
 // Timer interrupt for E. e_steps is set in the main routine.
 
 FORCE_INLINE void advance_isr() {
-    if (step_events_completed.wide > LA_decelerate_after && current_adv_steps > final_adv_steps) {
+    if (current_adv_steps > target_adv_steps) {
         // decompression
         e_steps -= e_step_loops;
         if (e_steps) WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR);
@@ -908,7 +936,7 @@ FORCE_INLINE void advance_isr() {
             current_adv_steps = 0;
         nextAdvanceISR = eISR_Rate;
     }
-    else if (step_events_completed.wide < LA_decelerate_after && current_adv_steps < max_adv_steps) {
+    else if (current_adv_steps < target_adv_steps) {
         // compression
         e_steps += e_step_loops;
         if (e_steps) WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR);
@@ -1233,9 +1261,6 @@ void st_init()
   nextMainISR = 0;
   nextAdvanceISR = ADV_NEVER;
   main_Rate = ADV_NEVER;
-  e_steps = 0;
-  e_step_loops = 1;
-  LA_phase = -1;
   current_adv_steps = 0;
 #endif