From fb8e880734bb099b80b031ee2b876e628a50135e Mon Sep 17 00:00:00 2001
From: Sebastianv650 <sebastian_v650@kabelmail.de>
Date: Wed, 4 May 2016 18:53:17 +0200
Subject: [PATCH] Add LIN_ADVANCE

---
 Marlin/Configuration_adv.h |   9 +++
 Marlin/Marlin_main.cpp     |  16 ++++++
 Marlin/planner.cpp         |  12 ++++
 Marlin/planner.h           |   4 ++
 Marlin/stepper.cpp         | 113 ++++++++++++++++++++++++++++++++++++-
 Marlin/stepper.h           |  27 ++++++++-
 6 files changed, 178 insertions(+), 3 deletions(-)

diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index 952da0fa7e..b90a2ee7e2 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -457,6 +457,15 @@
   #define MESH_MAX_Y (Y_MAX_POS - (MESH_INSET))
 #endif
 
+//Implementation of a linear pressure control
+//Assumption: advance = k * (delta velocity)
+//K=0 means advance disabled. A good value for a gregs wade extruder will be around K=75
+#define LIN_ADVANCE
+
+#if ENABLED(LIN_ADVANCE)
+  #define LIN_K 75
+#endif
+
 // @section extras
 
 // Arc interpretation settings:
diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp
index 73c7478377..e48ef2e59e 100644
--- a/Marlin/Marlin_main.cpp
+++ b/Marlin/Marlin_main.cpp
@@ -6468,6 +6468,16 @@ inline void gcode_M503() {
 
 #endif // DUAL_X_CARRIAGE
 
+#if ENABLED(LIN_ADVANCE)
+/**
+ * M905: Set advance factor
+ */
+inline void gcode_M905() {
+  stepper.synchronize();
+  stepper.advance_M905();
+}
+#endif
+
 /**
  * M907: Set digital trimpot motor current using axis codes X, Y, Z, E, B, S
  */
@@ -7339,6 +7349,12 @@ void process_next_command() {
           gcode_M605();
           break;
       #endif // DUAL_X_CARRIAGE
+      
+      #if ENABLED(LIN_ADVANCE)
+        case 905: // M905 Set advance factor.
+          gcode_M905();
+          break;
+      #endif
 
       case 907: // M907 Set digital trimpot motor current using axis codes.
         gcode_M907();
diff --git a/Marlin/planner.cpp b/Marlin/planner.cpp
index bd60d75a1f..a0489c99fd 100644
--- a/Marlin/planner.cpp
+++ b/Marlin/planner.cpp
@@ -1045,6 +1045,18 @@ void Planner::check_axes_activity() {
   // the maximum junction speed and may always be ignored for any speed reduction checks.
   block->nominal_length_flag = (block->nominal_speed <= v_allowable);
   block->recalculate_flag = true; // Always calculate trapezoid for new block
+  
+  #ifdef LIN_ADVANCE
+    //bse = allsteps: A problem occures if there is a very tiny move before a retract.
+    //In this case, the retract and the move will be executed together. This leads to an enormus amount advance steps due to a hughe e_acceleration.
+    //The math is correct, but you don't want a retract move done with advance! This situation has to be filtered out.
+    if ((!bse || (!bsx && !bsy && !bsz)) || (stepper.get_advance_k() == 0) || (bse == allsteps)) {
+      block->use_advance_lead = false;
+    } else {
+      block->use_advance_lead = true;
+      block->e_speed_multiplier8 = (block->steps[E_AXIS] << 8) / block->step_event_count;
+    }
+  #endif
 
   // Update previous path unit_vector and nominal speed
   for (int i = 0; i < NUM_AXIS; i++) previous_speed[i] = current_speed[i];
diff --git a/Marlin/planner.h b/Marlin/planner.h
index 07de37134e..5c0d5e12aa 100644
--- a/Marlin/planner.h
+++ b/Marlin/planner.h
@@ -70,6 +70,10 @@ typedef struct {
     volatile long final_advance;
     float advance;
   #endif
+  #ifdef LIN_ADVANCE
+    bool use_advance_lead;
+    int e_speed_multiplier8; //factorised by 2^8 to avoid float
+  #endif
 
   // Fields used by the motion planner to manage acceleration
   float nominal_speed,                               // The nominal speed for this block in mm/sec
diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp
index f8e8a853c9..46d0f21e9d 100644
--- a/Marlin/stepper.cpp
+++ b/Marlin/stepper.cpp
@@ -351,6 +351,22 @@ void Stepper::isr() {
           e_steps[current_block->active_extruder] += motor_direction(E_AXIS) ? -1 : 1;
         }
       #endif //ADVANCE
+      
+      #if ENABLED(LIN_ADVANCE)
+        counter_E += current_block->steps[E_AXIS];
+        if (counter_E > 0) {
+          counter_E -= current_block->step_event_count;
+          count_position[_AXIS(E)] += count_direction[_AXIS(E)];
+          e_steps[current_block->active_extruder] += motor_direction(E_AXIS) ? -1 : 1;
+        }
+        
+        if (current_block->use_advance_lead){
+          int delta_adv_steps; //Maybe a char would be enough?
+          delta_adv_steps = (((long)extruder_advance_k * current_estep_rate[current_block->active_extruder]) >> 9) - current_adv_steps[current_block->active_extruder];
+          e_steps[current_block->active_extruder] += delta_adv_steps;
+          current_adv_steps[current_block->active_extruder] += delta_adv_steps;
+        }
+      #endif //LIN_ADVANCE
 
       #define _COUNTER(AXIS) counter_## AXIS
       #define _APPLY_STEP(AXIS) AXIS ##_APPLY_STEP
@@ -363,7 +379,7 @@ void Stepper::isr() {
       STEP_ADD(X);
       STEP_ADD(Y);
       STEP_ADD(Z);
-      #if DISABLED(ADVANCE)
+      #if (DISABLED(ADVANCE) && DISABLED(LIN_ADVANCE))
         STEP_ADD(E);
       #endif
 
@@ -377,7 +393,7 @@ void Stepper::isr() {
       STEP_IF_COUNTER(X);
       STEP_IF_COUNTER(Y);
       STEP_IF_COUNTER(Z);
-      #if DISABLED(ADVANCE)
+      #if (DISABLED(ADVANCE) && DISABLED(LIN_ADVANCE))
         STEP_IF_COUNTER(E);
       #endif
 
@@ -398,6 +414,12 @@ void Stepper::isr() {
       timer = calc_timer(acc_step_rate);
       OCR1A = timer;
       acceleration_time += timer;
+      
+      #if ENABLED(LIN_ADVANCE)
+        if (current_block->use_advance_lead){
+          current_estep_rate[current_block->active_extruder] = ((unsigned long)acc_step_rate * current_block->e_speed_multiplier8) >> 8;
+        }
+      #endif
 
       #if ENABLED(ADVANCE)
 
@@ -424,6 +446,12 @@ void Stepper::isr() {
       timer = calc_timer(step_rate);
       OCR1A = timer;
       deceleration_time += timer;
+      
+      #if ENABLED(LIN_ADVANCE)
+        if (current_block->use_advance_lead){
+          current_estep_rate[current_block->active_extruder] = ((unsigned long)step_rate * current_block->e_speed_multiplier8) >> 8;
+        }
+      #endif
 
       #if ENABLED(ADVANCE)
         advance -= advance_rate * step_loops;
@@ -436,6 +464,12 @@ void Stepper::isr() {
       #endif //ADVANCE
     }
     else {
+      #ifdef LIN_ADVANCE
+        if (current_block->use_advance_lead){
+          current_estep_rate[current_block->active_extruder] = final_estep_rate;
+        }
+      #endif
+      
       OCR1A = OCR1A_nominal;
       // ensure we're running at the correct step rate, even if we just came off an acceleration
       step_loops = step_loops_nominal;
@@ -491,6 +525,55 @@ void Stepper::isr() {
 
 #endif // ADVANCE
 
+#if ENABLED(LIN_ADVANCE)
+unsigned char old_OCR0A;
+// Timer interrupt for E. e_steps is set in the main routine;
+// Timer 0 is shared with millies
+ISR(TIMER0_COMPA_vect) { stepper.advance_isr(); }
+
+void Stepper::advance_isr() {
+  old_OCR0A += 52; // ~10kHz interrupt (250000 / 26 = 9615kHz) war 52
+  OCR0A = old_OCR0A;
+
+#define STEP_E_ONCE(INDEX) \
+  if (e_steps[INDEX] != 0) { \
+    E## INDEX ##_STEP_WRITE(INVERT_E_STEP_PIN); \
+    if (e_steps[INDEX] < 0) { \
+      E## INDEX ##_DIR_WRITE(INVERT_E## INDEX ##_DIR); \
+      e_steps[INDEX]++; \
+    } \
+    else if (e_steps[INDEX] > 0) { \
+      E## INDEX ##_DIR_WRITE(!INVERT_E## INDEX ##_DIR); \
+      e_steps[INDEX]--; \
+    } \
+    E## INDEX ##_STEP_WRITE(!INVERT_E_STEP_PIN); \
+  }
+
+  // Step all E steppers that have steps, up to 4 steps per interrupt
+  for (unsigned char i = 0; i < 4; i++) {
+    #if EXTRUDERS > 3
+      switch(current_block->active_extruder){case 3:STEP_E_ONCE(3);break;case 2:STEP_E_ONCE(2);break;case 1:STEP_E_ONCE(1);break;default:STEP_E_ONCE(0);}
+    #elif EXTRUDERS > 2
+      switch(current_block->active_extruder){case 2:STEP_E_ONCE(2);break;case 1:STEP_E_ONCE(1);break;default:STEP_E_ONCE(0);}
+    #elif EXTRUDERS > 1
+      #if DISABLED(DUAL_X_CARRIAGE)
+        if(current_block->active_extruder == 1){STEP_E_ONCE(1)}else{STEP_E_ONCE(0);}
+      #else
+        extern bool extruder_duplication_enabled;
+        if(extruder_duplication_enabled){
+          STEP_E_ONCE(0);
+          STEP_E_ONCE(1);
+        }else {
+          if(current_block->active_extruder == 1){STEP_E_ONCE(1)}else{STEP_E_ONCE(0);}
+        }
+      #endif
+    #else
+      STEP_E_ONCE(0);
+    #endif
+  }
+}
+#endif // LIN_ADVANCE
+
 void Stepper::init() {
 
   digipot_init(); //Initialize Digipot Motor Current
@@ -655,6 +738,18 @@ void Stepper::init() {
   OCR1A = 0x4000;
   TCNT1 = 0;
   ENABLE_STEPPER_DRIVER_INTERRUPT();
+  
+  #if ENABLED(LIN_ADVANCE)
+    for (int i = 0; i < EXTRUDERS; i++){
+      e_steps[i] = 0;
+      current_adv_steps[i] = 0;
+    }
+    #if defined(TCCR0A) && defined(WGM01)
+      CBI(TCCR0A, WGM01);
+      CBI(TCCR0A, WGM00);
+    #endif
+    SBI(TIMSK0, OCIE0A);
+  #endif //LIN_ADVANCE
 
   #if ENABLED(ADVANCE)
     #if defined(TCCR0A) && defined(WGM01)
@@ -1040,3 +1135,17 @@ void Stepper::microstep_readings() {
     SERIAL_PROTOCOLLN(digitalRead(E1_MS2_PIN));
   #endif
 }
+
+#if ENABLED(LIN_ADVANCE)
+  void Stepper::advance_M905() {
+    if (code_seen('K')) extruder_advance_k = code_value();
+    SERIAL_ECHO_START;
+    SERIAL_ECHOPGM("Advance factor:");
+    SERIAL_CHAR(' ');
+    SERIAL_ECHOLN(extruder_advance_k);
+  }
+
+  int Stepper::get_advance_k(){
+    return extruder_advance_k;
+  }
+#endif
diff --git a/Marlin/stepper.h b/Marlin/stepper.h
index 1aebe366c0..e9d1191bc3 100644
--- a/Marlin/stepper.h
+++ b/Marlin/stepper.h
@@ -93,6 +93,10 @@ class Stepper {
     #if ENABLED(ADVANCE)
       static long e_steps[EXTRUDERS];
     #endif
+    
+    #if ENABLED(LIN_ADVANCE)
+      int extruder_advance_k = LIN_K;
+    #endif
 
   private:
 
@@ -111,6 +115,14 @@ class Stepper {
       static unsigned char old_OCR0A;
       static long advance_rate, advance, old_advance, final_advance;
     #endif
+    
+    #if ENABLED(LIN_ADVANCE)
+      unsigned char old_OCR0A;
+      volatile int e_steps[EXTRUDERS];
+      int final_estep_rate;
+      int current_estep_rate[EXTRUDERS]; //Actual extruder speed [steps/s]
+      int current_adv_steps[EXTRUDERS]; //The amount of current added esteps due to advance. Think of it as the current amount of pressure applied to the spring (=filament).
+    #endif
 
     static long acceleration_time, deceleration_time;
     //unsigned long accelerate_until, decelerate_after, acceleration_rate, initial_rate, final_rate, nominal_rate;
@@ -159,6 +171,12 @@ class Stepper {
     #if ENABLED(ADVANCE)
       static void advance_isr();
     #endif
+    
+    #if ENABLED(LIN_ADVANCE)
+      void advance_isr();
+      void advance_M905();
+      int get_advance_k();
+    #endif
 
     //
     // Block until all buffered steps are executed
@@ -315,6 +333,13 @@ class Stepper {
       acc_step_rate = current_block->initial_rate;
       acceleration_time = calc_timer(acc_step_rate);
       OCR1A = acceleration_time;
+      
+      #if ENABLED(LIN_ADVANCE)
+        if (current_block->use_advance_lead){
+          current_estep_rate[current_block->active_extruder] = ((unsigned long)acc_step_rate * current_block->e_speed_multiplier8) >> 8;
+          final_estep_rate = (current_block->nominal_rate * current_block->e_speed_multiplier8) >> 8;
+        }
+      #endif
 
       // SERIAL_ECHO_START;
       // SERIAL_ECHOPGM("advance :");
@@ -332,4 +357,4 @@ class Stepper {
 
 };
 
-#endif // STEPPER_H
\ No newline at end of file
+#endif // STEPPER_H
-- 
GitLab