ソースを参照

Improvements for Laser / Spindle (#17661)

Luu Lac 4年前
コミット
eda2fd8dbe
コミッターのメールアドレスに関連付けられたアカウントが存在しません

+ 27
- 19
Marlin/Configuration_adv.h ファイルの表示

@@ -2777,7 +2777,7 @@
2777 2777
 #if EITHER(SPINDLE_FEATURE, LASER_FEATURE)
2778 2778
   #define SPINDLE_LASER_ACTIVE_HIGH     false  // Set to "true" if the on/off function is active HIGH
2779 2779
   #define SPINDLE_LASER_PWM             true   // Set to "true" if your controller supports setting the speed/power
2780
-  #define SPINDLE_LASER_PWM_INVERT      true   // Set to "true" if the speed/power goes up when you want it to go slower
2780
+  #define SPINDLE_LASER_PWM_INVERT      false  // Set to "true" if the speed/power goes up when you want it to go slower
2781 2781
 
2782 2782
   #define SPINDLE_LASER_FREQUENCY       2500   // (Hz) Spindle/laser frequency (only on supported HALs: AVR and LPC)
2783 2783
 
@@ -2787,13 +2787,17 @@
2787 2787
    *  - PERCENT (S0 - S100)
2788 2788
    *  - RPM     (S0 - S50000)  Best for use with a spindle
2789 2789
    */
2790
-  #define CUTTER_POWER_DISPLAY PWM255
2790
+  #define CUTTER_POWER_UNIT PWM255
2791 2791
 
2792 2792
   /**
2793
-   * Relative mode uses relative range (SPEED_POWER_MIN to SPEED_POWER_MAX) instead of normal range (0 to SPEED_POWER_MAX)
2794
-   * Best use with SuperPID router controller where for example S0 = 5,000 RPM and S255 = 30,000 RPM
2793
+   * Relative Cutter Power
2794
+   * Normally, 'M3 O<power>' sets
2795
+   * OCR power is relative to the range SPEED_POWER_MIN...SPEED_POWER_MAX.
2796
+   * so input powers of 0...255 correspond to SPEED_POWER_MIN...SPEED_POWER_MAX
2797
+   * instead of normal range (0 to SPEED_POWER_MAX).
2798
+   * Best used with (e.g.) SuperPID router controller: S0 = 5,000 RPM and S255 = 30,000 RPM
2795 2799
    */
2796
-  //#define CUTTER_POWER_RELATIVE              // Set speed proportional to [SPEED_POWER_MIN...SPEED_POWER_MAX] instead of directly
2800
+  //#define CUTTER_POWER_RELATIVE              // Set speed proportional to [SPEED_POWER_MIN...SPEED_POWER_MAX]
2797 2801
 
2798 2802
   #if ENABLED(SPINDLE_FEATURE)
2799 2803
     //#define SPINDLE_CHANGE_DIR               // Enable if your spindle controller can change spindle direction
@@ -2804,25 +2808,25 @@
2804 2808
     #define SPINDLE_LASER_POWERDOWN_DELAY 5000 // (ms) Delay to allow the spindle to stop
2805 2809
 
2806 2810
     /**
2807
-     * M3/M4 uses the following equation to convert speed/power to PWM duty cycle
2808
-     * Power = ((DC / 255 * 100) - SPEED_POWER_INTERCEPT)) * (1 / SPEED_POWER_SLOPE)
2809
-     *   where PWM DC varies from 0 to 255
2811
+     * M3/M4 Power Equation
2810 2812
      *
2811
-     * Set these required parameters for your controller
2813
+     * Each tool uses different value ranges for speed / power control.
2814
+     * These parameters are used to convert between tool power units and PWM.
2815
+     *
2816
+     * Speed/Power = (PWMDC / 255 * 100 - SPEED_POWER_INTERCEPT) / SPEED_POWER_SLOPE
2817
+     * PWMDC = (spdpwr - SPEED_POWER_MIN) / (SPEED_POWER_MAX - SPEED_POWER_MIN) / SPEED_POWER_SLOPE
2812 2818
      */
2813
-    #define SPEED_POWER_SLOPE           118.4  // SPEED_POWER_SLOPE = SPEED_POWER_MAX / 255
2814
-    #define SPEED_POWER_INTERCEPT         0
2815
-    #define SPEED_POWER_MIN            5000
2816
-    #define SPEED_POWER_MAX           30000    // SuperPID router controller 0 - 30,000 RPM
2817
-    #define SPEED_POWER_STARTUP       25000    // The default value for speed power when M3 is called without arguments
2819
+    #define SPEED_POWER_INTERCEPT         0    // (%) 0-100 i.e., Minimum power percentage
2820
+    #define SPEED_POWER_MIN            5000    // (RPM)
2821
+    #define SPEED_POWER_MAX           30000    // (RPM) SuperPID router controller 0 - 30,000 RPM
2822
+    #define SPEED_POWER_STARTUP       25000    // (RPM) M3/M4 speed/power default (with no arguments)
2818 2823
 
2819 2824
   #else
2820 2825
 
2821
-    #define SPEED_POWER_SLOPE             0.3922 // SPEED_POWER_SLOPE = SPEED_POWER_MAX / 255
2822
-    #define SPEED_POWER_INTERCEPT         0
2823
-    #define SPEED_POWER_MIN               0
2824
-    #define SPEED_POWER_MAX             100    // 0-100%
2825
-    #define SPEED_POWER_STARTUP          80    // The default value for speed power when M3 is called without arguments
2826
+    #define SPEED_POWER_INTERCEPT         0    // (%) 0-100 i.e., Minimum power percentage
2827
+    #define SPEED_POWER_MIN               0    // (%) 0-100
2828
+    #define SPEED_POWER_MAX             100    // (%) 0-100
2829
+    #define SPEED_POWER_STARTUP          80    // (%) M3/M4 speed/power default (with no arguments)
2826 2830
 
2827 2831
     /**
2828 2832
      * Enable inline laser power to be handled in the planner / stepper routines.
@@ -2871,6 +2875,10 @@
2871 2875
         // Turn off the laser on G0 moves with no power parameter.
2872 2876
         // If a power parameter is provided, use that instead.
2873 2877
         //#define LASER_MOVE_G0_OFF
2878
+
2879
+        // Turn off the laser on G28 homing.
2880
+        //#define LASER_MOVE_G28_OFF
2881
+
2874 2882
       #endif
2875 2883
 
2876 2884
       /**

+ 50
- 0
Marlin/src/HAL/AVR/fastio.cpp ファイルの表示

@@ -234,5 +234,55 @@ uint8_t extDigitalRead(const int8_t pin) {
234 234
   }
235 235
 }
236 236
 
237
+#if 0
238
+/**
239
+ * Set Timer 5 PWM frequency in Hz, from 3.8Hz up to ~16MHz
240
+ * with a minimum resolution of 100 steps.
241
+ *
242
+ * DC values -1.0 to 1.0. Negative duty cycle inverts the pulse.
243
+ */
244
+uint16_t set_pwm_frequency_hz(const float &hz, const float dca, const float dcb, const float dcc) {
245
+  float count = 0;
246
+  if (hz > 0 && (dca || dcb || dcc)) {
247
+    count = float(F_CPU) / hz;            // 1x prescaler, TOP for 16MHz base freq.
248
+    uint16_t prescaler;                   // Range of 30.5Hz (65535) 64.5KHz (>31)
249
+
250
+         if (count >= 255. * 256.) { prescaler = 1024; SET_CS(5, PRESCALER_1024); }
251
+    else if (count >= 255. * 64.)  { prescaler = 256;  SET_CS(5,  PRESCALER_256); }
252
+    else if (count >= 255. * 8.)   { prescaler = 64;   SET_CS(5,   PRESCALER_64); }
253
+    else if (count >= 255.)        { prescaler = 8;    SET_CS(5,    PRESCALER_8); }
254
+    else                           { prescaler = 1;    SET_CS(5,    PRESCALER_1); }
255
+
256
+    count /= float(prescaler);
257
+    const float pwm_top = round(count);   // Get the rounded count
258
+
259
+    ICR5 = (uint16_t)pwm_top - 1;         // Subtract 1 for TOP
260
+    OCR5A = pwm_top * ABS(dca);          // Update and scale DCs
261
+    OCR5B = pwm_top * ABS(dcb);
262
+    OCR5C = pwm_top * ABS(dcc);
263
+    _SET_COM(5, A, dca ? (dca < 0 ? COM_SET_CLEAR : COM_CLEAR_SET) : COM_NORMAL); // Set compare modes
264
+    _SET_COM(5, B, dcb ? (dcb < 0 ? COM_SET_CLEAR : COM_CLEAR_SET) : COM_NORMAL);
265
+    _SET_COM(5, C, dcc ? (dcc < 0 ? COM_SET_CLEAR : COM_CLEAR_SET) : COM_NORMAL);
266
+
267
+    SET_WGM(5, FAST_PWM_ICRn);            // Fast PWM with ICR5 as TOP
268
+
269
+    //SERIAL_ECHOLNPGM("Timer 5 Settings:");
270
+    //SERIAL_ECHOLNPAIR("  Prescaler=", prescaler);
271
+    //SERIAL_ECHOLNPAIR("        TOP=", ICR5);
272
+    //SERIAL_ECHOLNPAIR("      OCR5A=", OCR5A);
273
+    //SERIAL_ECHOLNPAIR("      OCR5B=", OCR5B);
274
+    //SERIAL_ECHOLNPAIR("      OCR5C=", OCR5C);
275
+  }
276
+  else {
277
+    // Restore the default for Timer 5
278
+    SET_WGM(5, PWM_PC_8);                 // PWM 8-bit (Phase Correct)
279
+    SET_COMS(5, NORMAL, NORMAL, NORMAL);  // Do nothing
280
+    SET_CS(5, PRESCALER_64);              // 16MHz / 64 = 250KHz
281
+    OCR5A = OCR5B = OCR5C = 0;
282
+  }
283
+  return round(count);
284
+}
285
+#endif
286
+
237 287
 #endif // FASTIO_EXT_START
238 288
 #endif // __AVR__

+ 33
- 24
Marlin/src/feature/spindle_laser.cpp ファイルの表示

@@ -31,12 +31,13 @@
31 31
 #include "spindle_laser.h"
32 32
 
33 33
 SpindleLaser cutter;
34
+uint8_t SpindleLaser::power;
35
+bool SpindleLaser::isReady;                                           // Ready to apply power setting from the UI to OCR
36
+cutter_power_t SpindleLaser::menuPower,                               // Power set via LCD menu in PWM, PERCENT, or RPM
37
+               SpindleLaser::unitPower;                               // LCD status power in PWM, PERCENT, or RPM
34 38
 
35
-cutter_power_t SpindleLaser::power;
36
-bool SpindleLaser::isOn;                                                       // state to determine when to apply setPower to power
37
-cutter_setPower_t SpindleLaser::setPower = interpret_power(SPEED_POWER_MIN);   // spindle/laser speed/power control in PWM, Percentage or RPM
38 39
 #if ENABLED(MARLIN_DEV_MODE)
39
-  cutter_frequency_t SpindleLaser::frequency;                                  // setting PWM frequency; range: 2K - 50K
40
+  cutter_frequency_t SpindleLaser::frequency;                         // setting PWM frequency; range: 2K - 50K
40 41
 #endif
41 42
 #define SPINDLE_LASER_PWM_OFF ((SPINDLE_LASER_PWM_INVERT) ? 255 : 0)
42 43
 
@@ -44,13 +45,13 @@ cutter_setPower_t SpindleLaser::setPower = interpret_power(SPEED_POWER_MIN);   /
44 45
 // Init the cutter to a safe OFF state
45 46
 //
46 47
 void SpindleLaser::init() {
47
-  OUT_WRITE(SPINDLE_LASER_ENA_PIN, !SPINDLE_LASER_ACTIVE_HIGH); // Init spindle to off
48
+  OUT_WRITE(SPINDLE_LASER_ENA_PIN, !SPINDLE_LASER_ACTIVE_HIGH);       // Init spindle to off
48 49
   #if ENABLED(SPINDLE_CHANGE_DIR)
49
-    OUT_WRITE(SPINDLE_DIR_PIN, SPINDLE_INVERT_DIR ? 255 : 0);   // Init rotation to clockwise (M3)
50
+    OUT_WRITE(SPINDLE_DIR_PIN, SPINDLE_INVERT_DIR ? 255 : 0);         // Init rotation to clockwise (M3)
50 51
   #endif
51 52
   #if ENABLED(SPINDLE_LASER_PWM)
52 53
     SET_PWM(SPINDLE_LASER_PWM_PIN);
53
-    analogWrite(pin_t(SPINDLE_LASER_PWM_PIN), SPINDLE_LASER_PWM_OFF);  // set to lowest speed
54
+    analogWrite(pin_t(SPINDLE_LASER_PWM_PIN), SPINDLE_LASER_PWM_OFF); // set to lowest speed
54 55
   #endif
55 56
   #if ENABLED(HAL_CAN_SET_PWM_FREQ) && defined(SPINDLE_LASER_FREQUENCY)
56 57
     set_pwm_frequency(pin_t(SPINDLE_LASER_PWM_PIN), SPINDLE_LASER_FREQUENCY);
@@ -59,38 +60,47 @@ void SpindleLaser::init() {
59 60
 }
60 61
 
61 62
 #if ENABLED(SPINDLE_LASER_PWM)
62
-
63 63
   /**
64
-  * Set the cutter PWM directly to the given ocr value
65
-  **/
64
+   * Set the cutter PWM directly to the given ocr value
65
+   */
66 66
   void SpindleLaser::set_ocr(const uint8_t ocr) {
67
-    WRITE(SPINDLE_LASER_ENA_PIN, SPINDLE_LASER_ACTIVE_HIGH); // turn spindle on
67
+    WRITE(SPINDLE_LASER_ENA_PIN, SPINDLE_LASER_ACTIVE_HIGH);        // turn spindle on
68 68
     analogWrite(pin_t(SPINDLE_LASER_PWM_PIN), ocr ^ SPINDLE_LASER_PWM_OFF);
69 69
   }
70
-
70
+  void SpindleLaser::ocr_off() {
71
+    WRITE(SPINDLE_LASER_ENA_PIN, !SPINDLE_LASER_ACTIVE_HIGH);       // Turn spindle off
72
+    analogWrite(pin_t(SPINDLE_LASER_PWM_PIN), SPINDLE_LASER_PWM_OFF); // Only write low byte
73
+  }
71 74
 #endif
72 75
 
73 76
 //
74
-// Set cutter ON state (and PWM) to the given cutter power value
77
+// Set cutter ON/OFF state (and PWM) to the given cutter power value
75 78
 //
76
-void SpindleLaser::apply_power(const cutter_power_t inpow) {
77
-  static cutter_power_t last_power_applied = 0;
78
-  if (inpow == last_power_applied) return;
79
-  last_power_applied = inpow;
79
+void SpindleLaser::apply_power(const uint8_t opwr) {
80
+  static uint8_t last_power_applied = 0;
81
+  if (opwr == last_power_applied) return;
82
+  last_power_applied = opwr;
83
+  power = opwr;
80 84
   #if ENABLED(SPINDLE_LASER_PWM)
81
-    if (enabled())
82
-      set_ocr(translate_power(inpow));
85
+    if (cutter.unitPower == 0 && CUTTER_UNIT_IS(RPM)) {
86
+      ocr_off();
87
+      isReady = false;
88
+    }
89
+    else if (enabled() || ENABLED(CUTTER_POWER_RELATIVE)) {
90
+      set_ocr(power);
91
+      isReady = true;
92
+    }
83 93
     else {
84
-      WRITE(SPINDLE_LASER_ENA_PIN, !SPINDLE_LASER_ACTIVE_HIGH);                           // Turn spindle off
85
-      analogWrite(pin_t(SPINDLE_LASER_PWM_PIN), SPINDLE_LASER_PWM_OFF);                   // Only write low byte
94
+      ocr_off();
95
+      isReady = false;
86 96
     }
87 97
   #else
88
-    WRITE(SPINDLE_LASER_ENA_PIN, (SPINDLE_LASER_ACTIVE_HIGH) ? enabled() : !enabled());
98
+    WRITE(SPINDLE_LASER_ENA_PIN, enabled() == SPINDLE_LASER_ACTIVE_HIGH);
99
+    isReady = true;
89 100
   #endif
90 101
 }
91 102
 
92 103
 #if ENABLED(SPINDLE_CHANGE_DIR)
93
-
94 104
   //
95 105
   // Set the spindle direction and apply immediately
96 106
   // Stop on direction change if SPINDLE_STOP_ON_DIR_CHANGE is enabled
@@ -100,7 +110,6 @@ void SpindleLaser::apply_power(const cutter_power_t inpow) {
100 110
     if (TERN0(SPINDLE_STOP_ON_DIR_CHANGE, enabled()) && READ(SPINDLE_DIR_PIN) != dir_state) disable();
101 111
     WRITE(SPINDLE_DIR_PIN, dir_state);
102 112
   }
103
-
104 113
 #endif
105 114
 
106 115
 #endif // HAS_CUTTER

+ 179
- 75
Marlin/src/feature/spindle_laser.h ファイルの表示

@@ -34,87 +34,146 @@
34 34
   #include "../module/planner.h"
35 35
 #endif
36 36
 
37
+#define PCT_TO_PWM(X) ((X) * 255 / 100)
38
+
39
+#ifndef SPEED_POWER_INTERCEPT
40
+  #define SPEED_POWER_INTERCEPT 0
41
+#endif
42
+#define SPEED_POWER_FLOOR TERN(CUTTER_POWER_RELATIVE, SPEED_POWER_MIN, 0)
43
+
44
+// #define _MAP(N,S1,S2,D1,D2) ((N)*_MAX((D2)-(D1),0)/_MAX((S2)-(S1),1)+(D1))
45
+
37 46
 class SpindleLaser {
38 47
 public:
39
-  static bool isOn;                             //  state to determine when to apply setPower to power
40
-  static cutter_power_t power;
41
-  static cutter_setPower_t setPower;            //  spindle/laser menu set power; in PWM, Percentage or RPM
42
-  #if ENABLED(MARLIN_DEV_MODE)
43
-    static cutter_frequency_t frequency;        //  set PWM frequency; range: 2K-50K
44
-  #endif
48
+  static constexpr float
49
+    min_pct = round(TERN(CUTTER_POWER_RELATIVE, 0, (100 * float(SPEED_POWER_MIN) / TERN(SPINDLE_FEATURE, float(SPEED_POWER_MAX), 100)))),
50
+    max_pct = round(TERN(SPINDLE_FEATURE, 100, float(SPEED_POWER_MAX)));
45 51
 
46
-  static cutter_setPower_t interpret_power(const float pwr) {     // convert speed/power to configured PWM, Percentage or RPM in relative or normal range
47
-    #if CUTTER_DISPLAY_IS(PERCENT)
48
-      return (pwr / SPEED_POWER_MAX) * 100;                                               // to percent
49
-    #elif CUTTER_DISPLAY_IS(RPM)                                                          // to RPM is unaltered
50
-      return pwr;
51
-    #else                                                                                 // to PWM
52
-      #if ENABLED(CUTTER_POWER_RELATIVE)
53
-        return (pwr - SPEED_POWER_MIN) / (SPEED_POWER_MAX - SPEED_POWER_MIN) * 255;     // using rpm range as relative percentage
54
-      #else
55
-        return (pwr / SPEED_POWER_MAX) * 255;
56
-      #endif
57
-    #endif
52
+  static const inline uint8_t pct_to_ocr(const float pct) { return uint8_t(PCT_TO_PWM(pct)); }
53
+
54
+  // cpower = configured values (ie SPEED_POWER_MAX)
55
+  static const inline uint8_t cpwr_to_pct(const cutter_cpower_t cpwr) { // configured value to pct
56
+    return unitPower ? round(100 * (cpwr - SPEED_POWER_FLOOR) / (SPEED_POWER_MAX - SPEED_POWER_FLOOR)) : 0;
58 57
   }
59
-  /**
60
-  * Translate speed/power --> percentage --> PWM value
61
-  **/
62
-  static cutter_power_t translate_power(const float pwr) {
63
-    float pwrpc;
64
-    #if CUTTER_DISPLAY_IS(PERCENT)
65
-      pwrpc = pwr;
66
-    #elif CUTTER_DISPLAY_IS(RPM)            // RPM to percent
67
-     #if ENABLED(CUTTER_POWER_RELATIVE)
68
-        pwrpc = (pwr - SPEED_POWER_MIN) / (SPEED_POWER_MAX - SPEED_POWER_MIN) * 100;
69
-      #else
70
-        pwrpc = pwr / SPEED_POWER_MAX * 100;
71
-      #endif
72
-    #else
73
-      return pwr;                           // PWM
74
-    #endif
75 58
 
76
-    #if ENABLED(SPINDLE_FEATURE)
77
-      #if ENABLED(CUTTER_POWER_RELATIVE)
78
-        constexpr float spmin = 0;
59
+  // Convert a configured value (cpower)(ie SPEED_POWER_STARTUP) to unit power (upwr, upower),
60
+  // which can be PWM, Percent, or RPM (rel/abs).
61
+  static const inline cutter_power_t cpwr_to_upwr(const cutter_cpower_t cpwr) { // STARTUP power to Unit power
62
+    const cutter_power_t upwr = (
63
+      #if ENABLED(SPINDLE_FEATURE)
64
+        // Spindle configured values are in RPM
65
+        #if CUTTER_UNIT_IS(RPM)
66
+          cpwr                            // to RPM
67
+        #elif CUTTER_UNIT_IS(PERCENT)     // to PCT
68
+          cpwr_to_pct(cpwr)
69
+        #else                             // to PWM
70
+          PCT_TO_PWM(cpwr_to_pct(cpwr))
71
+        #endif
79 72
       #else
80
-        constexpr float spmin = SPEED_POWER_MIN / SPEED_POWER_MAX * 100; // convert to percentage
73
+        // Laser configured values are in PCT
74
+        #if CUTTER_UNIT_IS(PWM255)
75
+          PCT_TO_PWM(cpwr)
76
+        #else
77
+          cpwr                            // to RPM/PCT
78
+        #endif
81 79
       #endif
82
-      constexpr float spmax = 100;
83
-    #else
84
-      constexpr float spmin = SPEED_POWER_MIN;
85
-      constexpr float spmax = SPEED_POWER_MAX;
86
-    #endif
87
-
88
-    constexpr float inv_slope = RECIPROCAL(SPEED_POWER_SLOPE),
89
-                    min_ocr = (spmin - (SPEED_POWER_INTERCEPT)) * inv_slope,         // Minimum allowed
90
-                    max_ocr = (spmax - (SPEED_POWER_INTERCEPT)) * inv_slope;         // Maximum allowed
91
-    float ocr_val;
92
-    if (pwrpc < spmin) ocr_val = min_ocr;                                           // Use minimum if set below
93
-    else if (pwrpc > spmax) ocr_val = max_ocr;                                      // Use maximum if set above
94
-    else ocr_val = (pwrpc - (SPEED_POWER_INTERCEPT)) * inv_slope;                   // Use calculated OCR value
95
-    return ocr_val;                                                                 // ...limited to Atmel PWM max
80
+    );
81
+    return upwr;
96 82
   }
97 83
 
84
+  static const cutter_power_t mpower_min() { return cpwr_to_upwr(SPEED_POWER_MIN); }
85
+  static const cutter_power_t mpower_max() { return cpwr_to_upwr(SPEED_POWER_MAX); }
86
+
87
+  static bool isReady;                    // Ready to apply power setting from the UI to OCR
88
+  static uint8_t power;
89
+
90
+  #if ENABLED(MARLIN_DEV_MODE)
91
+    static cutter_frequency_t frequency;  // Set PWM frequency; range: 2K-50K
92
+  #endif
93
+
94
+  static cutter_power_t menuPower;        // Power as set via LCD menu in PWM, Percentage or RPM
95
+  static cutter_power_t unitPower;        // Power as displayed status in PWM, Percentage or RPM
96
+
98 97
   static void init();
99 98
 
100
-  // Modifying this function should update everywhere
101
-  static inline bool enabled(const cutter_power_t pwr) { return pwr > 0; }
102
-  static inline bool enabled() { return enabled(power); }
103 99
   #if ENABLED(MARLIN_DEV_MODE)
104 100
     static inline void refresh_frequency() { set_pwm_frequency(pin_t(SPINDLE_LASER_PWM_PIN), frequency); }
105 101
   #endif
106
-  static void apply_power(const cutter_power_t inpow);
102
+
103
+  // Modifying this function should update everywhere
104
+  static inline bool enabled(const cutter_power_t opwr) { return opwr > 0; }
105
+  static inline bool enabled() { return enabled(power); }
106
+
107
+  static void apply_power(const uint8_t inpow);
107 108
 
108 109
   FORCE_INLINE static void refresh() { apply_power(power); }
109
-  FORCE_INLINE static void set_power(const cutter_power_t pwr) { power = pwr; refresh(); }
110
+  FORCE_INLINE static void set_power(const uint8_t upwr) { power = upwr; refresh(); }
110 111
 
111
-  static inline void set_enabled(const bool enable) { set_power(enable ? (power ?: interpret_power(SPEED_POWER_STARTUP)) : 0); }
112
+  static inline void set_enabled(const bool enable) { set_power(enable ? (power ?: (unitPower ? upower_to_ocr(cpwr_to_upwr(SPEED_POWER_STARTUP)) : 0)) : 0); }
112 113
 
113 114
   #if ENABLED(SPINDLE_LASER_PWM)
115
+
114 116
     static void set_ocr(const uint8_t ocr);
115
-    static inline void set_ocr_power(const uint8_t pwr) { power = pwr; set_ocr(pwr); }
116
-    // static uint8_t translate_power(const cutter_power_t pwr); // Used by update output for power->OCR translation
117
-  #endif
117
+    static inline void set_ocr_power(const uint8_t ocr) { power = ocr; set_ocr(ocr); }
118
+    static void ocr_off();
119
+    // Used to update output for power->OCR translation
120
+    static inline uint8_t upower_to_ocr(const cutter_power_t upwr) {
121
+      return (
122
+        #if CUTTER_UNIT_IS(PWM255)
123
+          uint8_t(upwr)
124
+        #elif CUTTER_UNIT_IS(PERCENT)
125
+          pct_to_ocr(upwr)
126
+        #else
127
+          uint8_t(pct_to_ocr(cpwr_to_pct(upwr)))
128
+        #endif
129
+      );
130
+    }
131
+
132
+    // Correct power to configured range
133
+    static inline cutter_power_t power_to_range(const cutter_power_t pwr) {
134
+      return power_to_range(pwr, (
135
+        #if CUTTER_UNIT_IS(PWM255)
136
+          0
137
+        #elif CUTTER_UNIT_IS(PERCENT)
138
+          1
139
+        #elif CUTTER_UNIT_IS(RPM)
140
+          2
141
+        #else
142
+          #error "???"
143
+        #endif
144
+      ));
145
+    }
146
+    static inline cutter_power_t power_to_range(const cutter_power_t pwr, const uint8_t pwrUnit) {
147
+      if (pwr <= 0) return 0;
148
+      cutter_power_t upwr;
149
+      switch (pwrUnit) {
150
+        case 0:                                                 // PWM
151
+          upwr = (
152
+              (pwr < pct_to_ocr(min_pct)) ? pct_to_ocr(min_pct) // Use minimum if set below
153
+            : (pwr > pct_to_ocr(max_pct)) ? pct_to_ocr(max_pct) // Use maximum if set above
154
+            :  pwr
155
+          );
156
+          break;
157
+        case 1:                                                 // PERCENT
158
+          upwr = (
159
+              (pwr < min_pct) ? min_pct                         // Use minimum if set below
160
+            : (pwr > max_pct) ? max_pct                         // Use maximum if set above
161
+            :  pwr                                              // PCT
162
+          );
163
+          break;
164
+        case 2:                                                 // RPM
165
+          upwr = (
166
+              (pwr < SPEED_POWER_MIN) ? SPEED_POWER_MIN         // Use minimum if set below
167
+            : (pwr > SPEED_POWER_MAX) ? SPEED_POWER_MAX         // Use maximum if set above
168
+            : pwr                                               // Calculate OCR value
169
+          );
170
+          break;
171
+        default: break;
172
+      }
173
+      return upwr;
174
+    }
175
+
176
+  #endif // SPINDLE_LASER_PWM
118 177
 
119 178
   // Wait for spindle to spin up or spin down
120 179
   static inline void power_delay(const bool on) {
@@ -129,37 +188,82 @@ public:
129 188
     static inline void set_direction(const bool) {}
130 189
   #endif
131 190
 
132
-  static inline void disable() { isOn = false; set_enabled(false); }
191
+  static inline void disable() { isReady = false; set_enabled(false); }
192
+
133 193
   #if HAS_LCD_MENU
134
-    static inline void enable_forward() { isOn = true; setPower ? (power = setPower) : (setPower = interpret_power(SPEED_POWER_STARTUP)); set_direction(false); set_enabled(true); }
135
-    static inline void enable_reverse() { isOn = true; setPower ? (power = setPower) : (setPower = interpret_power(SPEED_POWER_STARTUP)); set_direction(true); set_enabled(true); }
194
+
195
+    static inline void enable_with_dir(const bool reverse) {
196
+      isReady = true;
197
+      const uint8_t ocr = upower_to_ocr(menuPower);
198
+      if (menuPower)
199
+        power = ocr;
200
+      else
201
+        menuPower = cpwr_to_upwr(SPEED_POWER_STARTUP);
202
+      unitPower = menuPower;
203
+      set_direction(reverse);
204
+      set_enabled(true);
205
+    }
206
+    FORCE_INLINE static void enable_forward() { enable_with_dir(false); }
207
+    FORCE_INLINE static void enable_reverse() { enable_with_dir(true); }
208
+
209
+    #if ENABLED(SPINDLE_LASER_PWM)
210
+      static inline void update_from_mpower() {
211
+        if (isReady) power = upower_to_ocr(menuPower);
212
+        unitPower = menuPower;
213
+      }
214
+    #endif
215
+
136 216
   #endif
137 217
 
138 218
   #if ENABLED(LASER_POWER_INLINE)
219
+    /**
220
+     * Inline power adds extra fields to the planner block
221
+     * to handle laser power and scale to movement speed.
222
+     */
223
+
139 224
     // Force disengage planner power control
140
-    static inline void inline_disable() { planner.laser.status = 0; planner.laser.power = 0; isOn = false;}
225
+    static inline void inline_disable()	{
226
+      isReady = false;
227
+      unitPower = 0;
228
+      planner.laser_inline.status = 0;
229
+      planner.laser_inline.power = 0;
230
+    }
141 231
 
142 232
     // Inline modes of all other functions; all enable planner inline power control
143
-    static inline void inline_enabled(const bool enable) { enable ? inline_power(SPEED_POWER_STARTUP) : inline_ocr_power(0); }
233
+    static inline void set_inline_enabled(const bool enable) {
234
+      if (enable) { inline_power(cpwr_to_upwr(SPEED_POWER_STARTUP)); }
235
+      else { unitPower = 0; isReady = false; menuPower = 0; TERN(SPINDLE_LASER_PWM, inline_ocr_power, inline_power)(0);}
236
+    }
144 237
 
145
-    static void inline_power(const cutter_power_t pwr) {
238
+    // Set the power for subsequent movement blocks
239
+    static void inline_power(const cutter_power_t upwr) {
240
+      unitPower = upwr;
241
+      menuPower = unitPower;
146 242
       #if ENABLED(SPINDLE_LASER_PWM)
147
-        inline_ocr_power(translate_power(pwr));
243
+          isReady = true;
244
+        #if ENABLED(SPEED_POWER_RELATIVE) && !CUTTER_UNIT_IS(RPM) // relative mode does not turn laser off at 0, except for RPM
245
+          planner.laser_inline.status = 0x03;
246
+          planner.laser_inline.power = upower_to_ocr(upwr);
247
+        #else
248
+          if (upwr > 0)
249
+            inline_ocr_power(upower_to_ocr(upwr));
250
+        #endif
148 251
       #else
149
-        planner.laser.status = enabled(pwr) ? 0x03 : 0x01;
150
-        planner.laser.power = pwr;
252
+        planner.laser_inline.status = enabled(pwr) ? 0x03 : 0x01;
253
+        planner.laser_inline.power = pwr;
254
+        isReady = enabled(upwr);
151 255
       #endif
152 256
     }
153 257
 
154
-    static inline void inline_direction(const bool reverse) { UNUSED(reverse); } // TODO is this ever going to be needed
258
+    static inline void inline_direction(const bool) { /* never */ }
155 259
 
156 260
     #if ENABLED(SPINDLE_LASER_PWM)
157
-      static inline void inline_ocr_power(const uint8_t pwr) {
158
-        planner.laser.status = pwr ? 0x03 : 0x01;
159
-        planner.laser.power = pwr;
261
+      static inline void inline_ocr_power(const uint8_t ocrpwr) {
262
+        planner.laser_inline.status = ocrpwr ? 0x03 : 0x01;
263
+        planner.laser_inline.power = ocrpwr;
160 264
       }
161 265
     #endif
162
-  #endif
266
+  #endif  // LASER_POWER_INLINE
163 267
 
164 268
   static inline void kill() {
165 269
     TERN_(LASER_POWER_INLINE, inline_disable());

+ 12
- 11
Marlin/src/feature/spindle_laser_types.h ファイルの表示

@@ -34,19 +34,20 @@
34 34
   #define _MSG_CUTTER(M) MSG_LASER_##M
35 35
 #endif
36 36
 #define MSG_CUTTER(M) _MSG_CUTTER(M)
37
-#if CUTTER_DISPLAY_IS(RPM) && SPEED_POWER_MAX > 255
38
-  #define cutter_power_t              uint16_t
39
-  #define cutter_setPower_t           uint16_t
40
-  #define CUTTER_MENU_POWER_TYPE      uint16_5
41
-  #define cutter_power2str            ui16tostr5rj
37
+
38
+typedef IF<(SPEED_POWER_MAX > 255), uint16_t, uint8_t>::type cutter_cpower_t;
39
+
40
+#if CUTTER_UNIT_IS(RPM) && SPEED_POWER_MAX > 255
41
+  typedef uint16_t cutter_power_t;
42
+  #define CUTTER_MENU_POWER_TYPE uint16_5
43
+  #define cutter_power2str       ui16tostr5rj
42 44
 #else
43
-  #define cutter_power_t              uint8_t
44
-  #define cutter_setPower_t           uint8_t
45
-  #define CUTTER_MENU_POWER_TYPE      uint8
46
-  #define cutter_power2str            ui8tostr3rj
45
+  typedef uint8_t cutter_power_t;
46
+  #define CUTTER_MENU_POWER_TYPE uint8
47
+  #define cutter_power2str       ui8tostr3rj
47 48
 #endif
48 49
 
49 50
 #if ENABLED(MARLIN_DEV_MODE)
50
-  #define cutter_frequency_t          uint16_t
51
-  #define CUTTER_MENU_FREQUENCY_TYPE  uint16_5
51
+  typedef uint16_t cutter_frequency_t;
52
+  #define CUTTER_MENU_FREQUENCY_TYPE uint16_5
52 53
 #endif

+ 9
- 0
Marlin/src/gcode/calibrate/G28.cpp ファイルの表示

@@ -51,6 +51,10 @@
51 51
   #include "../../libs/L64XX/L64XX_Marlin.h"
52 52
 #endif
53 53
 
54
+#if ENABLED(LASER_MOVE_G28_OFF)
55
+  #include "../../feature/spindle_laser.h"
56
+#endif
57
+
54 58
 #define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE)
55 59
 #include "../../core/debug_out.h"
56 60
 
@@ -195,6 +199,11 @@
195 199
  *
196 200
  */
197 201
 void GcodeSuite::G28() {
202
+
203
+#if ENABLED(LASER_MOVE_G28_OFF)
204
+  cutter.set_inline_enabled(false);       // turn off laser
205
+#endif
206
+
198 207
   if (DEBUGGING(LEVELING)) {
199 208
     DEBUG_ECHOLNPGM(">>> G28");
200 209
     log_machine_info();

+ 23
- 22
Marlin/src/gcode/control/M3-M5.cpp ファイルの表示

@@ -28,28 +28,18 @@
28 28
 #include "../../feature/spindle_laser.h"
29 29
 #include "../../module/stepper.h"
30 30
 
31
-inline cutter_power_t get_s_power() {
32
-  return cutter_power_t(
33
-    parser.intval('S', cutter.interpret_power(SPEED_POWER_STARTUP))
34
-  );
35
-}
36
-
37 31
 /**
38 32
  * Laser:
39
- *
40 33
  *  M3 - Laser ON/Power (Ramped power)
41 34
  *  M4 - Laser ON/Power (Continuous power)
42 35
  *
43
- *    S<power> - Set power. S0 will turn the laser off.
44
- *    O<ocr>   - Set power and OCR
45
- *
46 36
  * Spindle:
47
- *
48 37
  *  M3 - Spindle ON (Clockwise)
49 38
  *  M4 - Spindle ON (Counter-clockwise)
50 39
  *
51
- *    S<power> - Set power. S0 will turn the spindle off.
52
- *    O<ocr>   - Set power and OCR
40
+ * Parameters:
41
+ *  S<power> - Set power. S0 will turn the spindle/laser off, except in relative mode.
42
+ *  O<ocr>   - Set power and OCR (oscillator count register)
53 43
  *
54 44
  *  If no PWM pin is defined then M3/M4 just turns it on.
55 45
  *
@@ -76,17 +66,25 @@ inline cutter_power_t get_s_power() {
76 66
  *  PWM duty cycle goes from 0 (off) to 255 (always on).
77 67
  */
78 68
 void GcodeSuite::M3_M4(const bool is_M4) {
69
+  auto get_s_power = [] {
70
+    if (parser.seen('S'))
71
+      cutter.unitPower = cutter.power_to_range(cutter_power_t(round(parser.value_float())));
72
+    else
73
+      cutter.unitPower = cutter.cpwr_to_upwr(SPEED_POWER_STARTUP);
74
+    return cutter.unitPower;
75
+  };
79 76
 
80 77
   #if ENABLED(LASER_POWER_INLINE)
81 78
     if (parser.seen('I') == DISABLED(LASER_POWER_INLINE_INVERT)) {
82 79
       // Laser power in inline mode
83 80
       cutter.inline_direction(is_M4); // Should always be unused
84
-
85 81
       #if ENABLED(SPINDLE_LASER_PWM)
86
-        if (parser.seen('O'))
87
-          cutter.inline_ocr_power(parser.value_byte()); // The OCR is a value from 0 to 255 (uint8_t)
82
+        if (parser.seen('O')) {
83
+          cutter.unitPower = cutter.power_to_range(parser.value_byte(), 0);
84
+          cutter.inline_ocr_power(cutter.unitPower); // The OCR is a value from 0 to 255 (uint8_t)
85
+        }
88 86
         else
89
-          cutter.inline_power(get_s_power());
87
+          cutter.inline_power(cutter.upower_to_ocr(get_s_power()));
90 88
       #else
91 89
         cutter.inline_enabled(true);
92 90
       #endif
@@ -97,17 +95,19 @@ void GcodeSuite::M3_M4(const bool is_M4) {
97 95
   #endif
98 96
 
99 97
   planner.synchronize();   // Wait for previous movement commands (G0/G0/G2/G3) to complete before changing power
100
-
101 98
   cutter.set_direction(is_M4);
102 99
 
103 100
   #if ENABLED(SPINDLE_LASER_PWM)
104
-    if (parser.seenval('O'))
105
-      cutter.set_ocr_power(parser.value_byte()); // The OCR is a value from 0 to 255 (uint8_t)
101
+    if (parser.seenval('O')) {
102
+      cutter.unitPower = cutter.power_to_range(parser.value_byte(), 0);
103
+      cutter.set_ocr_power(cutter.unitPower); // The OCR is a value from 0 to 255 (uint8_t)
104
+    }
106 105
     else
107
-      cutter.set_power(get_s_power());
106
+      cutter.set_power(cutter.upower_to_ocr(get_s_power()));
108 107
   #else
109 108
     cutter.set_enabled(true);
110 109
   #endif
110
+  cutter.menuPower = cutter.unitPower;
111 111
 }
112 112
 
113 113
 /**
@@ -116,7 +116,7 @@ void GcodeSuite::M3_M4(const bool is_M4) {
116 116
 void GcodeSuite::M5() {
117 117
   #if ENABLED(LASER_POWER_INLINE)
118 118
     if (parser.seen('I') == DISABLED(LASER_POWER_INLINE_INVERT)) {
119
-      cutter.inline_enabled(false); // Laser power in inline mode
119
+      cutter.set_inline_enabled(false); // Laser power in inline mode
120 120
       return;
121 121
     }
122 122
     // Non-inline, standard case
@@ -124,6 +124,7 @@ void GcodeSuite::M5() {
124 124
   #endif
125 125
   planner.synchronize();
126 126
   cutter.set_enabled(false);
127
+  cutter.menuPower = cutter.unitPower;
127 128
 }
128 129
 
129 130
 #endif // HAS_CUTTER

+ 3
- 7
Marlin/src/gcode/gcode.cpp ファイルの表示

@@ -180,13 +180,9 @@ void GcodeSuite::get_destination_from_command() {
180 180
   #if ENABLED(LASER_MOVE_POWER)
181 181
     // Set the laser power in the planner to configure this move
182 182
     if (parser.seen('S'))
183
-      cutter.inline_power(parser.value_int());
184
-    else {
185
-      #if ENABLED(LASER_MOVE_G0_OFF)
186
-        if (parser.codenum == 0)        // G0
187
-          cutter.inline_enabled(false);
188
-      #endif
189
-    }
183
+      cutter.inline_power(cutter.power_to_range(cutter_power_t(round(parser.value_float()))));
184
+    else if (ENABLED(LASER_MOVE_G0_OFF) && parser.codenum == 0) // G0
185
+      cutter.set_inline_enabled(false);
190 186
   #endif
191 187
 }
192 188
 

+ 5
- 5
Marlin/src/inc/Conditionals_adv.h ファイルの表示

@@ -142,11 +142,11 @@
142 142
 //
143 143
 #if EITHER(SPINDLE_FEATURE, LASER_FEATURE)
144 144
   #define HAS_CUTTER 1
145
-  #define _CUTTER_DISP_PWM255  1
146
-  #define _CUTTER_DISP_PERCENT 2
147
-  #define _CUTTER_DISP_RPM     3
148
-  #define _CUTTER_DISP(V)      _CAT(_CUTTER_DISP_, V)
149
-  #define CUTTER_DISPLAY_IS(V) (_CUTTER_DISP(CUTTER_POWER_DISPLAY) == _CUTTER_DISP(V))
145
+  #define _CUTTER_POWER_PWM255  1
146
+  #define _CUTTER_POWER_PERCENT 2
147
+  #define _CUTTER_POWER_RPM     3
148
+  #define _CUTTER_POWER(V)      _CAT(_CUTTER_POWER_, V)
149
+  #define CUTTER_UNIT_IS(V)    (_CUTTER_POWER(CUTTER_POWER_UNIT)    == _CUTTER_POWER(V))
150 150
 #endif
151 151
 
152 152
 // Add features that need hardware PWM here

+ 7
- 5
Marlin/src/inc/SanityCheck.h ファイルの表示

@@ -421,6 +421,8 @@
421 421
   #error "SPINDLE_STOP_ON_DIR_CHANGE is now SPINDLE_CHANGE_DIR_STOP. Please update your Configuration_adv.h."
422 422
 #elif defined(SPINDLE_LASER_ENABLE_INVERT)
423 423
   #error "SPINDLE_LASER_ENABLE_INVERT is now SPINDLE_LASER_ACTIVE_HIGH. Please update your Configuration_adv.h."
424
+#elif defined(CUTTER_POWER_DISPLAY)
425
+  #error "CUTTER_POWER_DISPLAY is now CUTTER_POWER_UNIT. Please update your Configuration_adv.h."
424 426
 #elif defined(CHAMBER_HEATER_PIN)
425 427
   #error "CHAMBER_HEATER_PIN is now HEATER_CHAMBER_PIN. Please update your configuration and/or pins."
426 428
 #elif defined(TMC_Z_CALIBRATION)
@@ -2825,10 +2827,10 @@ static_assert(   _ARR_TEST(3,0) && _ARR_TEST(3,1) && _ARR_TEST(3,2)
2825 2827
 #endif
2826 2828
 
2827 2829
 #if HAS_CUTTER
2828
-  #ifndef CUTTER_POWER_DISPLAY
2829
-    #error "CUTTER_POWER_DISPLAY is required with a spindle or laser. Please update your Configuration_adv.h."
2830
-  #elif !CUTTER_DISPLAY_IS(PWM255) && !CUTTER_DISPLAY_IS(PERCENT) && !CUTTER_DISPLAY_IS(RPM)
2831
-    #error "CUTTER_POWER_DISPLAY must be PWM255, PERCENT, or RPM. Please update your Configuration_adv.h."
2830
+  #ifndef CUTTER_POWER_UNIT
2831
+    #error "CUTTER_POWER_UNIT is required with a spindle or laser. Please update your Configuration_adv.h."
2832
+  #elif !CUTTER_UNIT_IS(PWM255) && !CUTTER_UNIT_IS(PERCENT) && !CUTTER_UNIT_IS(RPM)
2833
+    #error "CUTTER_POWER_UNIT must be PWM255, PERCENT, or RPM. Please update your Configuration_adv.h."
2832 2834
   #endif
2833 2835
 
2834 2836
   #if ENABLED(LASER_POWER_INLINE)
@@ -2878,7 +2880,7 @@ static_assert(   _ARR_TEST(3,0) && _ARR_TEST(3,1) && _ARR_TEST(3,2)
2878 2880
       #error "SPINDLE_LASER_PWM_PIN not assigned to a PWM pin."
2879 2881
     #elif !defined(SPINDLE_LASER_PWM_INVERT)
2880 2882
       #error "SPINDLE_LASER_PWM_INVERT is required for (SPINDLE|LASER)_FEATURE."
2881
-    #elif !defined(SPEED_POWER_SLOPE) || !defined(SPEED_POWER_INTERCEPT) || !defined(SPEED_POWER_MIN) || !defined(SPEED_POWER_MAX) || !defined(SPEED_POWER_STARTUP)
2883
+    #elif !(defined(SPEED_POWER_INTERCEPT) && defined(SPEED_POWER_MIN) && defined(SPEED_POWER_MAX) && defined(SPEED_POWER_STARTUP))
2882 2884
       #error "SPINDLE_LASER_PWM equation constant(s) missing."
2883 2885
     #elif _PIN_CONFLICT(X_MIN)
2884 2886
       #error "SPINDLE_LASER_PWM pin conflicts with X_MIN_PIN."

+ 7
- 4
Marlin/src/lcd/dogm/status_screen_DOGM.cpp ファイルの表示

@@ -541,12 +541,15 @@ void MarlinUI::draw_status_screen() {
541 541
 
542 542
     // Laser / Spindle
543 543
     #if DO_DRAW_CUTTER
544
-      if (cutter.power && PAGE_CONTAINS(STATUS_CUTTER_TEXT_Y - INFO_FONT_ASCENT, STATUS_CUTTER_TEXT_Y - 1)) {
545
-        lcd_put_u8str(STATUS_CUTTER_TEXT_X, STATUS_CUTTER_TEXT_Y, cutter_power2str(cutter.power));
546
-        #if CUTTER_DISPLAY_IS(PERCENT)
544
+      if (cutter.isReady && PAGE_CONTAINS(STATUS_CUTTER_TEXT_Y - INFO_FONT_ASCENT, STATUS_CUTTER_TEXT_Y - 1)) {
545
+        #if CUTTER_UNIT_IS(PERCENT)
546
+          lcd_put_u8str(STATUS_CUTTER_TEXT_X, STATUS_CUTTER_TEXT_Y, cutter_power2str(cutter.unitPower));
547 547
           lcd_put_wchar('%');
548
-        #elif CUTTER_DISPLAY_IS(RPM)
548
+        #elif CUTTER_UNIT_IS(RPM)
549
+          lcd_put_u8str(STATUS_CUTTER_TEXT_X - 2, STATUS_CUTTER_TEXT_Y, ftostr51rj(float(cutter.unitPower) / 1000));
549 550
           lcd_put_wchar('K');
551
+        #else
552
+          lcd_put_u8str(STATUS_CUTTER_TEXT_X, STATUS_CUTTER_TEXT_Y, cutter_power2str(cutter.unitPower));
550 553
         #endif
551 554
       }
552 555
     #endif

+ 0
- 1
Marlin/src/lcd/menu/menu_main.cpp ファイルの表示

@@ -73,7 +73,6 @@ void menu_configuration();
73 73
 #endif
74 74
 
75 75
 #if HAS_CUTTER
76
-  #include "../../feature/spindle_laser.h"
77 76
   void menu_spindle_laser();
78 77
 #endif
79 78
 

+ 7
- 7
Marlin/src/lcd/menu/menu_spindle_laser.cpp ファイルの表示

@@ -34,19 +34,19 @@
34 34
 
35 35
   void menu_spindle_laser() {
36 36
 
37
-    const bool can_disable = cutter.enabled() && cutter.isOn;
37
+    const bool is_enabled = cutter.enabled() && cutter.isReady;
38 38
 
39 39
     START_MENU();
40 40
     BACK_ITEM(MSG_MAIN);
41 41
 
42 42
     #if ENABLED(SPINDLE_LASER_PWM)
43
-      EDIT_ITEM_FAST( CUTTER_MENU_POWER_TYPE, MSG_CUTTER(POWER), &cutter.setPower
44
-                    , cutter.interpret_power(SPEED_POWER_MIN), cutter.interpret_power(SPEED_POWER_MAX)
45
-                    , []{ if (cutter.isOn) cutter.power = cutter.setPower; }
46
-      );
43
+      // Change the cutter's "current power" value without turning the cutter on or off
44
+      // Power is displayed and set in units and range according to CUTTER_POWER_UNIT
45
+      EDIT_ITEM_FAST(CUTTER_MENU_POWER_TYPE, MSG_CUTTER(POWER), &cutter.menuPower,
46
+        cutter.mpower_min(), cutter.mpower_max(), cutter.update_from_mpower);
47 47
     #endif
48 48
 
49
-    if (can_disable)
49
+    if (is_enabled)
50 50
       ACTION_ITEM(MSG_CUTTER(OFF), cutter.disable);
51 51
     else {
52 52
       ACTION_ITEM(MSG_CUTTER(ON), cutter.enable_forward);
@@ -57,7 +57,7 @@
57 57
 
58 58
     #if ENABLED(MARLIN_DEV_MODE)
59 59
       #if ENABLED(HAL_CAN_SET_PWM_FREQ) && defined(SPINDLE_LASER_FREQUENCY)
60
-        EDIT_ITEM_FAST(CUTTER_MENU_FREQUENCY_TYPE, MSG_CUTTER_FREQUENCY, &cutter.frequency, 2000, 50000,[]{ cutter.refresh_frequency();});
60
+        EDIT_ITEM_FAST(CUTTER_MENU_FREQUENCY_TYPE, MSG_CUTTER_FREQUENCY, &cutter.frequency, 2000, 50000, cutter.refresh_frequency);
61 61
       #endif
62 62
     #endif
63 63
     END_MENU();

+ 4
- 4
Marlin/src/module/planner.cpp ファイルの表示

@@ -129,7 +129,7 @@ uint8_t Planner::delay_before_delivering;       // This counter delays delivery
129 129
 planner_settings_t Planner::settings;           // Initialized by settings.load()
130 130
 
131 131
 #if ENABLED(LASER_POWER_INLINE)
132
-  laser_state_t Planner::laser;              // Current state for blocks
132
+  laser_state_t Planner::laser_inline;          // Current state for blocks
133 133
 #endif
134 134
 
135 135
 uint32_t Planner::max_acceleration_steps_per_s2[XYZE_N]; // (steps/s^2) Derived from mm_per_s2
@@ -1693,7 +1693,7 @@ bool Planner::_buffer_steps(const xyze_long_t &target
1693 1693
  *  fr_mm_s     - (target) speed of the move
1694 1694
  *  extruder    - target extruder
1695 1695
  *
1696
- * Returns true is movement is acceptable, false otherwise
1696
+ * Returns true if movement is acceptable, false otherwise
1697 1697
  */
1698 1698
 bool Planner::_populate_block(block_t * const block, bool split_move,
1699 1699
   const abce_long_t &target
@@ -1803,8 +1803,8 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
1803 1803
 
1804 1804
   // Update block laser power
1805 1805
   #if ENABLED(LASER_POWER_INLINE)
1806
-    block->laser.status = laser.status;
1807
-    block->laser.power = laser.power;
1806
+    block->laser.status = laser_inline.status;
1807
+    block->laser.power = laser_inline.power;
1808 1808
   #endif
1809 1809
 
1810 1810
   // Number of steps for each axis

+ 15
- 11
Marlin/src/module/planner.h ファイルの表示

@@ -117,8 +117,15 @@ enum BlockFlag : char {
117 117
 #if ENABLED(LASER_POWER_INLINE)
118 118
 
119 119
   typedef struct {
120
-    uint8_t status,           // See planner settings for meaning
121
-            power;            // Ditto; When in trapezoid mode this is nominal power
120
+    bool isPlanned:1;
121
+    bool isEnabled:1;
122
+    bool dir:1;
123
+    bool Reserved:6;
124
+  } power_status_t;
125
+
126
+  typedef struct {
127
+    power_status_t status;    // See planner settings for meaning
128
+    uint8_t power;            // Ditto; When in trapezoid mode this is nominal power
122 129
     #if ENABLED(LASER_POWER_INLINE_TRAPEZOID)
123 130
       uint8_t   power_entry;  // Entry power for the laser
124 131
       #if DISABLED(LASER_POWER_INLINE_TRAPEZOID_CONT)
@@ -234,18 +241,15 @@ typedef struct block_t {
234 241
 #if ENABLED(LASER_POWER_INLINE)
235 242
   typedef struct {
236 243
     /**
237
-     * Laser status bitmask; most bits are unused;
238
-     *  0: Planner buffer enable
239
-     *  1: Laser enable
240
-     *  2: Reserved for direction
244
+     * Laser status flags
241 245
      */
242
-    uint8_t status;
246
+    power_status_t status;
243 247
     /**
244 248
      * Laser power: 0 or 255 in case of PWM-less laser,
245
-     * or the OCR value;
249
+     * or the OCR (oscillator count register) value;
246 250
      *
247
-     * Using OCR instead of raw power,
248
-     * as it avoids floating points during move loop
251
+     * Using OCR instead of raw power, because it avoids
252
+     * floating point operations during the move loop.
249 253
      */
250 254
     uint8_t power;
251 255
   } laser_state_t;
@@ -332,7 +336,7 @@ class Planner {
332 336
     static planner_settings_t settings;
333 337
 
334 338
     #if ENABLED(LASER_POWER_INLINE)
335
-      static laser_state_t laser;
339
+      static laser_state_t laser_inline;
336 340
     #endif
337 341
 
338 342
     static uint32_t max_acceleration_steps_per_s2[XYZE_N]; // (steps/s^2) Derived from mm_per_s2

+ 64
- 70
Marlin/src/module/stepper.cpp ファイルの表示

@@ -244,8 +244,8 @@ xyze_long_t Stepper::count_position{0};
244 244
 xyze_int8_t Stepper::count_direction{0};
245 245
 
246 246
 #if ENABLED(LASER_POWER_INLINE_TRAPEZOID)
247
-  Stepper::stepper_laser_t Stepper::laser = {
248
-    .trap_en = false,
247
+  Stepper::stepper_laser_t Stepper::laser_trap = {
248
+    .enabled = false,
249 249
     .cur_power = 0,
250 250
     .cruise_set = false,
251 251
     #if DISABLED(LASER_POWER_INLINE_TRAPEZOID_CONT)
@@ -1843,28 +1843,28 @@ uint32_t Stepper::block_phase_isr() {
1843 1843
 
1844 1844
         // Update laser - Accelerating
1845 1845
         #if ENABLED(LASER_POWER_INLINE_TRAPEZOID)
1846
-          if (laser.trap_en) {
1846
+          if (laser_trap.enabled) {
1847 1847
             #if DISABLED(LASER_POWER_INLINE_TRAPEZOID_CONT)
1848 1848
               if (current_block->laser.entry_per) {
1849
-                laser.acc_step_count -= step_events_completed - laser.last_step_count;
1850
-                laser.last_step_count = step_events_completed;
1849
+                laser_trap.acc_step_count -= step_events_completed - laser_trap.last_step_count;
1850
+                laser_trap.last_step_count = step_events_completed;
1851 1851
 
1852 1852
                 // Should be faster than a divide, since this should trip just once
1853
-                if (laser.acc_step_count < 0) {
1854
-                  while (laser.acc_step_count < 0) {
1855
-                    laser.acc_step_count += current_block->laser.entry_per;
1856
-                    if (laser.cur_power < current_block->laser.power) laser.cur_power++;
1853
+                if (laser_trap.acc_step_count < 0) {
1854
+                  while (laser_trap.acc_step_count < 0) {
1855
+                    laser_trap.acc_step_count += current_block->laser.entry_per;
1856
+                    if (laser_trap.cur_power < current_block->laser.power) laser_trap.cur_power++;
1857 1857
                   }
1858
-                  cutter.set_ocr_power(laser.cur_power);
1858
+                  cutter.set_ocr_power(laser_trap.cur_power);
1859 1859
                 }
1860 1860
               }
1861 1861
             #else
1862
-              if (laser.till_update)
1863
-                laser.till_update--;
1862
+              if (laser_trap.till_update)
1863
+                laser_trap.till_update--;
1864 1864
               else {
1865
-                laser.till_update = LASER_POWER_INLINE_TRAPEZOID_CONT_PER;
1866
-                laser.cur_power = (current_block->laser.power * acc_step_rate) / current_block->nominal_rate;
1867
-                cutter.set_ocr_power(laser.cur_power); // Cycle efficiency is irrelevant it the last line was many cycles
1865
+                laser_trap.till_update = LASER_POWER_INLINE_TRAPEZOID_CONT_PER;
1866
+                laser_trap.cur_power = (current_block->laser.power * acc_step_rate) / current_block->nominal_rate;
1867
+                cutter.set_ocr_power(laser_trap.cur_power); // Cycle efficiency is irrelevant it the last line was many cycles
1868 1868
               }
1869 1869
             #endif
1870 1870
           }
@@ -1920,28 +1920,28 @@ uint32_t Stepper::block_phase_isr() {
1920 1920
 
1921 1921
         // Update laser - Decelerating
1922 1922
         #if ENABLED(LASER_POWER_INLINE_TRAPEZOID)
1923
-          if (laser.trap_en) {
1923
+          if (laser_trap.enabled) {
1924 1924
             #if DISABLED(LASER_POWER_INLINE_TRAPEZOID_CONT)
1925 1925
               if (current_block->laser.exit_per) {
1926
-                laser.acc_step_count -= step_events_completed - laser.last_step_count;
1927
-                laser.last_step_count = step_events_completed;
1926
+                laser_trap.acc_step_count -= step_events_completed - laser_trap.last_step_count;
1927
+                laser_trap.last_step_count = step_events_completed;
1928 1928
 
1929 1929
                 // Should be faster than a divide, since this should trip just once
1930
-                if (laser.acc_step_count < 0) {
1931
-                  while (laser.acc_step_count < 0) {
1932
-                    laser.acc_step_count += current_block->laser.exit_per;
1933
-                    if (laser.cur_power > current_block->laser.power_exit) laser.cur_power--;
1930
+                if (laser_trap.acc_step_count < 0) {
1931
+                  while (laser_trap.acc_step_count < 0) {
1932
+                    laser_trap.acc_step_count += current_block->laser.exit_per;
1933
+                    if (laser_trap.cur_power > current_block->laser.power_exit) laser_trap.cur_power--;
1934 1934
                   }
1935
-                  cutter.set_ocr_power(laser.cur_power);
1935
+                  cutter.set_ocr_power(laser_trap.cur_power);
1936 1936
                 }
1937 1937
               }
1938 1938
             #else
1939
-              if (laser.till_update)
1940
-                laser.till_update--;
1939
+              if (laser_trap.till_update)
1940
+                laser_trap.till_update--;
1941 1941
               else {
1942
-                laser.till_update = LASER_POWER_INLINE_TRAPEZOID_CONT_PER;
1943
-                laser.cur_power = (current_block->laser.power * step_rate) / current_block->nominal_rate;
1944
-                cutter.set_ocr_power(laser.cur_power); // Cycle efficiency isn't relevant when the last line was many cycles
1942
+                laser_trap.till_update = LASER_POWER_INLINE_TRAPEZOID_CONT_PER;
1943
+                laser_trap.cur_power = (current_block->laser.power * step_rate) / current_block->nominal_rate;
1944
+                cutter.set_ocr_power(laser_trap.cur_power); // Cycle efficiency isn't relevant when the last line was many cycles
1945 1945
               }
1946 1946
             #endif
1947 1947
           }
@@ -1966,16 +1966,16 @@ uint32_t Stepper::block_phase_isr() {
1966 1966
 
1967 1967
         // Update laser - Cruising
1968 1968
         #if ENABLED(LASER_POWER_INLINE_TRAPEZOID)
1969
-          if (laser.trap_en) {
1970
-            if (!laser.cruise_set) {
1971
-              laser.cur_power = current_block->laser.power;
1972
-              cutter.set_ocr_power(laser.cur_power);
1973
-              laser.cruise_set = true;
1969
+          if (laser_trap.enabled) {
1970
+            if (!laser_trap.cruise_set) {
1971
+              laser_trap.cur_power = current_block->laser.power;
1972
+              cutter.set_ocr_power(laser_trap.cur_power);
1973
+              laser_trap.cruise_set = true;
1974 1974
             }
1975 1975
             #if ENABLED(LASER_POWER_INLINE_TRAPEZOID_CONT)
1976
-              laser.till_update = LASER_POWER_INLINE_TRAPEZOID_CONT_PER;
1976
+              laser_trap.till_update = LASER_POWER_INLINE_TRAPEZOID_CONT_PER;
1977 1977
             #else
1978
-              laser.last_step_count = step_events_completed;
1978
+              laser_trap.last_step_count = step_events_completed;
1979 1979
             #endif
1980 1980
           }
1981 1981
         #endif
@@ -2000,7 +2000,10 @@ uint32_t Stepper::block_phase_isr() {
2000 2000
           return interval; // No more queued movements!
2001 2001
       }
2002 2002
 
2003
-      TERN_(HAS_CUTTER, cutter.apply_power(current_block->cutter_power));
2003
+      // For non-inline cutter, grossly apply power
2004
+      #if ENABLED(LASER_FEATURE) && DISABLED(LASER_POWER_INLINE)
2005
+        cutter.apply_power(current_block->cutter_power);
2006
+      #endif
2004 2007
 
2005 2008
       TERN_(POWER_LOSS_RECOVERY, recovery.info.sdpos = current_block->sdpos);
2006 2009
 
@@ -2150,15 +2153,9 @@ uint32_t Stepper::block_phase_isr() {
2150 2153
         else LA_isr_rate = LA_ADV_NEVER;
2151 2154
       #endif
2152 2155
 
2153
-      if (
2154
-        #if HAS_L64XX
2155
-          true  // Always set direction for L64xx (This also enables the chips)
2156
-        #else
2157
-          current_block->direction_bits != last_direction_bits
2158
-          #if DISABLED(MIXING_EXTRUDER)
2159
-            || stepper_extruder != last_moved_extruder
2160
-          #endif
2161
-        #endif
2156
+      if ( ENABLED(HAS_L64XX)  // Always set direction for L64xx (Also enables the chips)
2157
+        || current_block->direction_bits != last_direction_bits
2158
+        || TERN(MIXING_EXTRUDER, false, stepper_extruder != last_moved_extruder)
2162 2159
       ) {
2163 2160
         last_direction_bits = current_block->direction_bits;
2164 2161
         #if EXTRUDERS > 1
@@ -2170,33 +2167,31 @@ uint32_t Stepper::block_phase_isr() {
2170 2167
       }
2171 2168
 
2172 2169
       #if ENABLED(LASER_POWER_INLINE)
2173
-        const uint8_t stat = current_block->laser.status;
2170
+        const power_status_t stat = current_block->laser.status;
2174 2171
         #if ENABLED(LASER_POWER_INLINE_TRAPEZOID)
2175
-          laser.trap_en = (stat & 0x03) == 0x03;
2176
-          laser.cur_power = current_block->laser.power_entry; // RESET STATE
2177
-          laser.cruise_set = false;
2172
+          laser_trap.enabled = stat.isPlanned && stat.isEnabled;
2173
+          laser_trap.cur_power = current_block->laser.power_entry; // RESET STATE
2174
+          laser_trap.cruise_set = false;
2178 2175
           #if DISABLED(LASER_POWER_INLINE_TRAPEZOID_CONT)
2179
-            laser.last_step_count = 0;
2180
-            laser.acc_step_count = current_block->laser.entry_per / 2;
2176
+            laser_trap.last_step_count = 0;
2177
+            laser_trap.acc_step_count = current_block->laser.entry_per / 2;
2181 2178
           #else
2182
-            laser.till_update = 0;
2179
+            laser_trap.till_update = 0;
2183 2180
           #endif
2184 2181
           // Always have PWM in this case
2185
-          if (TEST(stat, 0)) {                        // Planner controls the laser
2186
-            if (TEST(stat, 1))                        // Laser is on
2187
-              cutter.set_ocr_power(laser.cur_power);
2188
-            else
2189
-              cutter.set_power(0);
2182
+          if (stat.isPlanned) {                        // Planner controls the laser
2183
+            cutter.set_ocr_power(
2184
+              stat.isEnabled ? laser_trap.cur_power : 0 // ON with power or OFF
2185
+            );
2190 2186
           }
2191 2187
         #else
2192
-          if (TEST(stat, 0)) {                        // Planner controls the laser
2188
+          if (stat.isPlanned) {                        // Planner controls the laser
2193 2189
             #if ENABLED(SPINDLE_LASER_PWM)
2194
-              if (TEST(stat, 1))                      // Laser is on
2195
-                cutter.set_ocr_power(current_block->laser.power);
2196
-              else
2197
-                cutter.set_power(0);
2190
+              cutter.set_ocr_power(
2191
+                stat.isEnabled ? current_block->laser.power : 0 // ON with power or OFF
2192
+              );
2198 2193
             #else
2199
-              cutter.set_enabled(TEST(stat, 1));
2194
+              cutter.set_enabled(stat.isEnabled);
2200 2195
             #endif
2201 2196
           }
2202 2197
         #endif
@@ -2237,15 +2232,14 @@ uint32_t Stepper::block_phase_isr() {
2237 2232
     #if ENABLED(LASER_POWER_INLINE_CONTINUOUS)
2238 2233
       else { // No new block found; so apply inline laser parameters
2239 2234
         // This should mean ending file with 'M5 I' will stop the laser; thus the inline flag isn't needed
2240
-        const uint8_t stat = planner.laser.status;
2241
-        if (TEST(stat, 0)) {             // Planner controls the laser
2235
+        const power_status_t stat = planner.laser_inline.status;
2236
+        if (stat.isPlanned) {             // Planner controls the laser
2242 2237
           #if ENABLED(SPINDLE_LASER_PWM)
2243
-            if (TEST(stat, 1))           // Laser is on
2244
-              cutter.set_ocr_power(planner.laser.power);
2245
-            else
2246
-              cutter.set_power(0);
2238
+            cutter.set_ocr_power(
2239
+              stat.isEnabled ? planner.laser_inline.power : 0 // ON with power or OFF
2240
+            );
2247 2241
           #else
2248
-            cutter.set_enabled(TEST(stat, 1));
2242
+            cutter.set_enabled(stat.isEnabled);
2249 2243
           #endif
2250 2244
         }
2251 2245
       }

読み込み中…
キャンセル
保存