Browse Source

Add a Linear Advance 1.0->1.5 compatibility layer

Allow existing gcode using LA10 to transparently take advantage of LA15
by using a simple linear conversion function based on experimental
results with the MK3 implementation of linear advance.

Autodetect LA10 values based on the first M900 instruction contained in
the print. In order to support printing mixed files without resetting
the printer we also reset the autodetection status when starting a new
SD print and/or when explicitly disabling LA.

Since we cannot reliably detect whether a new print is started when
printing via USB, also reset the detection status when homing in G28,
which is generally performed once at each print. Note that this doesn't
clear the previous K value, it only allows a subsequent M900 to provide
LA10 values when printed after a LA15 file.
Yuri D'Elia 4 years ago
parent
commit
7b29ce29b4
4 changed files with 106 additions and 3 deletions
  1. 1 0
      Firmware/Configuration_adv.h
  2. 26 3
      Firmware/Marlin_main.cpp
  3. 40 0
      Firmware/la10compat.cpp
  4. 39 0
      Firmware/la10compat.h

+ 1 - 0
Firmware/Configuration_adv.h

@@ -287,6 +287,7 @@
 
 #ifdef LIN_ADVANCE
   #define LIN_ADVANCE_K 0  // Unit: mm compression per 1mm/s extruder speed
+  //#define LA_NOCOMPAT    // Disable Linear Advance 1.0 compatibility
   //#define LA_LIVE_K      // Allow adjusting K in the Tune menu
   //#define LA_DEBUG       // If enabled, this will generate debug information output over USB.
   //#define LA_DEBUG_LOGIC // @wavexx: setup logic channels for isr debugging

+ 26 - 3
Firmware/Marlin_main.cpp

@@ -83,6 +83,9 @@
 #include "Dcodes.h"
 #include "AutoDeplete.h"
 
+#ifndef LA_NOCOMPAT
+#include "la10compat.h"
+#endif
 
 #ifdef SWSPI
 #include "swspi.h"
@@ -2068,12 +2071,23 @@ static float probe_pt(float x, float y, float z_before) {
     */
 inline void gcode_M900() {
     st_synchronize();
-    
+
     const float newK = code_seen('K') ? code_value_float() : -1;
+#ifdef LA_NOCOMPAT
     if (newK >= 0 && newK < 10)
-      extruder_advance_K = newK;
+        extruder_advance_K = newK;
+    else
+        SERIAL_ECHOLNPGM("K out of allowed range!");
+#else
+    if (newK == 0) {
+        la10c_reset();
+        extruder_advance_K = 0;
+    }
+    else if(newK > 0)
+        extruder_advance_K = la10c_value(newK);
     else
-      SERIAL_ECHOLNPGM("K out of allowed range!");
+        SERIAL_ECHOLNPGM("K out of allowed range!");
+#endif
 
     SERIAL_ECHO_START;
     SERIAL_ECHOPGM("Advance K=");
@@ -4136,6 +4150,9 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
     // --------------------------------------------
     case 28: 
     {
+#ifndef LA_NOCOMPAT
+      la10c_reset();
+#endif
       long home_x_value = 0;
       long home_y_value = 0;
       long home_z_value = 0;
@@ -5372,6 +5389,9 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
       else
       {
           failstats_reset_print();
+#ifndef LA_NOCOMPAT
+          la10c_reset();
+#endif
           card.startFileprint();
           starttime=_millis();
       }
@@ -5465,6 +5485,9 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
         if(code_seen('S'))
           if(strchr_pointer<namestartpos) //only if "S" is occuring _before_ the filename
             card.setIndex(code_value_long());
+#ifndef LA_NOCOMPAT
+        la10c_reset();
+#endif
         card.startFileprint();
         if(!call_procedure)
           starttime=_millis(); //procedure calls count as normal print time.

+ 40 - 0
Firmware/la10compat.cpp

@@ -0,0 +1,40 @@
+#include "la10compat.h"
+#include "Marlin.h"
+
+
+static LA10C_MODE la10c_mode = LA10C_UNKNOWN;
+
+
+void la10c_mode_change(LA10C_MODE mode)
+{
+    if(mode == la10c_mode) return;
+
+    SERIAL_ECHOPGM("LA10C: Linear Advance mode: ");
+    switch(mode)
+    {
+    case LA10C_UNKNOWN: SERIAL_ECHOLNPGM("UNKNOWN"); break;
+    case LA10C_LA15:    SERIAL_ECHOLNPGM("1.5"); break;
+    case LA10C_LA10:    SERIAL_ECHOLNPGM("1.0"); break;
+    }
+    la10c_mode = mode;
+}
+
+
+// Approximate a LA10 value to a LA15 equivalent.
+static float la10c_convert(float k)
+{
+    float new_K = k * 0.004 - 0.06;
+    return (new_K < 0? 0: new_K);
+}
+
+
+float la10c_value(float k)
+{
+    if(la10c_mode == LA10C_UNKNOWN)
+        la10c_mode_change(k < 10? LA10C_LA15: LA10C_LA10);
+
+    if(la10c_mode == LA10C_LA15)
+        return k;
+    else
+        return la10c_convert(k);
+}

+ 39 - 0
Firmware/la10compat.h

@@ -0,0 +1,39 @@
+// la10compat: LA10->LA15 conversion
+//
+// When the current mode is UNKNOWN autodetection is active and any K<10
+// will set the mode to LA15, LA10 is set otherwise. When LA10
+// compatbility mode is active the K factor is converted to a LA15
+// equivalent (that is, the return value is always a LA15 value).
+//
+// Once the interpretation mode has been set it is kept until the mode
+// is explicitly reset. This is done to handle transparent fallback for
+// old firmware revisions in combination with the following gcode
+// sequence:
+//
+//   M900 K0.01 ; set LA15 value (interpreted by any firmware)
+//   M900 K10   ; set LA10 value (ignored by LA15 firmware)
+//
+// A LA15 firmware without this module will only parse the first
+// correctly, rejecting the second. A LA10 FW will parse both, but keep
+// the last value. Since the LA15 value, if present, corresponds to the
+// truth value, the compatibility stub needs to "lock" onto the first
+// seen value for the current print.
+//
+// The mode needs to be carefully reset for each print in order for
+// diffent versions of M900 to be interpreted independently.
+
+#pragma once
+
+enum __attribute__((packed)) LA10C_MODE
+{
+    LA10C_UNKNOWN = 0,
+    LA10C_LA15    = 1,
+    LA10C_LA10    = 2
+};
+
+// Explicitly set/reset the interpretation mode for la10c_value()
+void la10c_mode_change(LA10C_MODE mode);
+static inline void la10c_reset() { la10c_mode_change(LA10C_UNKNOWN); }
+
+// Return a LA15 K value according to the supplied value and mode
+float la10c_value(float k);