Browse Source

Spindle/Laser power in planner blocks (#14437)

Scott Lahteine 4 years ago
parent
commit
b7b303f4bf
No account linked to committer's email address

+ 2
- 2
Marlin/src/HAL/HAL_AVR/fast_pwm.cpp View File

@@ -23,7 +23,7 @@
23 23
 
24 24
 #include "../../inc/MarlinConfigPre.h"
25 25
 
26
-#if ENABLED(FAST_PWM_FAN)
26
+#if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_PWM
27 27
 
28 28
 #include "HAL.h"
29 29
 
@@ -278,5 +278,5 @@ void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255
278 278
   }
279 279
 }
280 280
 
281
-#endif // FAST_PWM_FAN
281
+#endif // FAST_PWM_FAN || SPINDLE_LASER_PWM
282 282
 #endif // __AVR__

+ 2
- 2
Marlin/src/HAL/HAL_LPC1768/fast_pwm.cpp View File

@@ -24,7 +24,7 @@
24 24
 
25 25
 #include "../../inc/MarlinConfigPre.h"
26 26
 
27
-#if ENABLED(FAST_PWM_FAN)
27
+#if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_PWM
28 28
 
29 29
 #include <pwm.h>
30 30
 
@@ -36,5 +36,5 @@ void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255
36 36
   pwm_write_ratio(pin, invert ? 1.0f - (float)v / v_size : (float)v / v_size);
37 37
 }
38 38
 
39
-#endif // FAST_PWM_FAN
39
+#endif // FAST_PWM_FAN || SPINDLE_LASER_PWM
40 40
 #endif // TARGET_LPC1768

+ 21
- 19
Marlin/src/feature/spindle_laser.cpp View File

@@ -34,14 +34,16 @@ SpindleLaser cutter;
34 34
 
35 35
 cutter_power_t SpindleLaser::power; // = 0
36 36
 
37
+#define SPINDLE_LASER_PWM_OFF ((SPINDLE_LASER_PWM_INVERT) ? 255 : 0)
38
+
37 39
 void SpindleLaser::init() {
38 40
   OUT_WRITE(SPINDLE_LASER_ENA_PIN, !SPINDLE_LASER_ACTIVE_HIGH); // Init spindle to off
39 41
   #if ENABLED(SPINDLE_CHANGE_DIR)
40 42
     OUT_WRITE(SPINDLE_DIR_PIN, SPINDLE_INVERT_DIR ? 255 : 0);   // Init rotation to clockwise (M3)
41 43
   #endif
42
-  #if ENABLED(SPINDLE_LASER_PWM) && PIN_EXISTS(SPINDLE_LASER_PWM)
44
+  #if ENABLED(SPINDLE_LASER_PWM)
43 45
     SET_PWM(SPINDLE_LASER_PWM_PIN);
44
-    analogWrite(pin_t(SPINDLE_LASER_PWM_PIN), SPINDLE_LASER_PWM_INVERT ? 255 : 0);  // set to lowest speed
46
+    analogWrite(pin_t(SPINDLE_LASER_PWM_PIN), SPINDLE_LASER_PWM_OFF);  // set to lowest speed
45 47
   #endif
46 48
 }
47 49
 
@@ -54,34 +56,34 @@ void SpindleLaser::init() {
54 56
    */
55 57
   void SpindleLaser::set_ocr(const uint8_t ocr) {
56 58
     WRITE(SPINDLE_LASER_ENA_PIN, SPINDLE_LASER_ACTIVE_HIGH); // turn spindle on (active low)
57
-    #if ENABLED(SPINDLE_LASER_PWM)
58
-      analogWrite(pin_t(SPINDLE_LASER_PWM_PIN), (SPINDLE_LASER_PWM_INVERT) ? 255 - ocr : ocr);
59
-    #endif
59
+    analogWrite(pin_t(SPINDLE_LASER_PWM_PIN), ocr ^ SPINDLE_LASER_PWM_OFF);
60 60
   }
61 61
 
62 62
 #endif
63 63
 
64
-void SpindleLaser::update_output() {
65
-  const bool ena = enabled();
64
+void SpindleLaser::apply_power(const cutter_power_t inpow) {
65
+  static cutter_power_t last_power_applied = 0;
66
+  if (inpow == last_power_applied) return;
67
+  last_power_applied = inpow;
66 68
   #if ENABLED(SPINDLE_LASER_PWM)
67
-    if (ena) {
69
+    if (enabled()) {
70
+      #define _scaled(F) ((F - (SPEED_POWER_INTERCEPT)) * inv_slope)
68 71
       constexpr float inv_slope = RECIPROCAL(SPEED_POWER_SLOPE),
69
-                      min_ocr = (SPEED_POWER_MIN - (SPEED_POWER_INTERCEPT)) * inv_slope,  // Minimum allowed
70
-                      max_ocr = (SPEED_POWER_MAX - (SPEED_POWER_INTERCEPT)) * inv_slope;  // Maximum allowed
72
+                      min_ocr = _scaled(SPEED_POWER_MIN),
73
+                      max_ocr = _scaled(SPEED_POWER_MAX);
71 74
       int16_t ocr_val;
72
-           if (power <= SPEED_POWER_MIN) ocr_val = min_ocr;                               // Use minimum if set below
73
-      else if (power >= SPEED_POWER_MAX) ocr_val = max_ocr;                               // Use maximum if set above
74
-      else ocr_val = (power - (SPEED_POWER_INTERCEPT)) * inv_slope;                       // Use calculated OCR value
75
-      set_ocr(ocr_val & 0xFF);                                                            // ...limited to Atmel PWM max
75
+           if (inpow <= SPEED_POWER_MIN) ocr_val = min_ocr;       // Use minimum if set below
76
+      else if (inpow >= SPEED_POWER_MAX) ocr_val = max_ocr;       // Use maximum if set above
77
+      else ocr_val = _scaled(inpow);                              // Use calculated OCR value
78
+      set_ocr(ocr_val & 0xFF);                                    // ...limited to Atmel PWM max
76 79
     }
77
-    else {                                                                                // Convert RPM to PWM duty cycle
78
-      WRITE(SPINDLE_LASER_ENA_PIN, !SPINDLE_LASER_ACTIVE_HIGH);                           // Turn spindle off (active low)
79
-      analogWrite(pin_t(SPINDLE_LASER_PWM_PIN), SPINDLE_LASER_PWM_INVERT ? 255 : 0);      // Only write low byte
80
+    else {
81
+      WRITE(SPINDLE_LASER_ENA_PIN, !SPINDLE_LASER_ACTIVE_HIGH);   // Turn spindle off (active low)
82
+      analogWrite(pin_t(SPINDLE_LASER_PWM_PIN), SPINDLE_LASER_PWM_OFF);  // Only write low byte
80 83
     }
81 84
   #else
82
-    WRITE(SPINDLE_LASER_ENA_PIN, ena ? SPINDLE_LASER_ACTIVE_HIGH : !SPINDLE_LASER_ACTIVE_HIGH);
85
+    WRITE(SPINDLE_LASER_ENA_PIN, (SPINDLE_LASER_ACTIVE_HIGH) ? enabled() : !enabled());
83 86
   #endif
84
-  power_delay(ena);
85 87
 }
86 88
 
87 89
 #if ENABLED(SPINDLE_CHANGE_DIR)

+ 18
- 6
Marlin/src/feature/spindle_laser.h View File

@@ -36,10 +36,10 @@
36 36
 #define MSG_CUTTER(M) _MSG_CUTTER(M)
37 37
 
38 38
 #if SPEED_POWER_MAX > 255
39
-  #define cutter_power_t   uint16_t
39
+  typedef uint16_t cutter_power_t;
40 40
   #define CUTTER_MENU_TYPE uint16_5
41 41
 #else
42
-  #define cutter_power_t   uint8_t
42
+  typedef uint8_t cutter_power_t;
43 43
   #define CUTTER_MENU_TYPE uint8
44 44
 #endif
45 45
 
@@ -51,9 +51,17 @@ public:
51 51
 
52 52
   static inline bool enabled() { return !!power; }
53 53
 
54
-  static inline void set_power(const uint8_t pwr) { power = pwr; update_output(); }
54
+  static inline void set_power(const cutter_power_t pwr) { power = pwr; }
55 55
 
56
-  static inline void set_enabled(const bool enable) { set_power(enable ? 255 : 0); }
56
+  static inline void refresh() { apply_power(power); }
57
+
58
+  static inline void set_enabled(const bool enable) {
59
+    const bool was = enabled();
60
+    set_power(enable ? 255 : 0);
61
+    if (was != enable) power_delay();
62
+  }
63
+
64
+  static void apply_power(const cutter_power_t inpow);
57 65
 
58 66
   //static bool active() { return READ(SPINDLE_LASER_ENA_PIN) == SPINDLE_LASER_ACTIVE_HIGH; }
59 67
 
@@ -61,11 +69,15 @@ public:
61 69
 
62 70
   #if ENABLED(SPINDLE_LASER_PWM)
63 71
     static void set_ocr(const uint8_t ocr);
64
-    static inline void set_ocr_power(const uint8_t pwr) { power = pwr; set_ocr(pwr); }
72
+    static inline void set_ocr_power(const cutter_power_t pwr) { power = pwr; set_ocr(pwr); }
65 73
   #endif
66 74
 
67 75
   // Wait for spindle to spin up or spin down
68
-  static inline void power_delay(const bool on) { safe_delay(on ? SPINDLE_LASER_POWERUP_DELAY : SPINDLE_LASER_POWERDOWN_DELAY); }
76
+  static inline void power_delay() {
77
+    #if SPINDLE_LASER_POWERUP_DELAY || SPINDLE_LASER_POWERDOWN_DELAY
78
+      safe_delay(enabled() ? SPINDLE_LASER_POWERUP_DELAY : SPINDLE_LASER_POWERDOWN_DELAY);
79
+    #endif
80
+  }
69 81
 
70 82
   #if ENABLED(SPINDLE_CHANGE_DIR)
71 83
     static void set_direction(const bool reverse);

+ 20
- 6
Marlin/src/gcode/control/M3-M5.cpp View File

@@ -29,10 +29,20 @@
29 29
 #include "../../module/stepper.h"
30 30
 
31 31
 /**
32
- *  M3 - Cutter ON (Clockwise)
33
- *  M4 - Cutter ON (Counter-clockwise)
32
+ * Laser:
34 33
  *
35
- *    S<power> - Set power. S0 turns it off.
34
+ *  M3 - Laser ON/Power (Ramped power)
35
+ *  M4 - Laser ON/Power (Continuous power)
36
+ *
37
+ *    S<power> - Set power. S0 will turn the laser off.
38
+ *    O<ocr>   - Set power and OCR
39
+ *
40
+ * Spindle:
41
+ *
42
+ *  M3 - Spindle ON (Clockwise)
43
+ *  M4 - Spindle ON (Counter-clockwise)
44
+ *
45
+ *    S<power> - Set power. S0 will turn the spindle off.
36 46
  *    O<ocr>   - Set power and OCR
37 47
  *
38 48
  *  If no PWM pin is defined then M3/M4 just turns it on.
@@ -61,12 +71,14 @@
61 71
  */
62 72
 void GcodeSuite::M3_M4(const bool is_M4) {
63 73
 
64
-  planner.synchronize();   // Wait for previous movement commands (G0/G0/G2/G3) to complete before changing power
74
+  #if ENABLED(SPINDLE_FEATURE)
75
+    planner.synchronize();   // Wait for movement to complete before changing power
76
+  #endif
65 77
 
66 78
   cutter.set_direction(is_M4);
67 79
 
68 80
   #if ENABLED(SPINDLE_LASER_PWM)
69
-    if (parser.seen('O'))
81
+    if (parser.seenval('O'))
70 82
       cutter.set_ocr_power(parser.value_byte()); // The OCR is a value from 0 to 255 (uint8_t)
71 83
     else
72 84
       cutter.set_power(parser.intval('S', 255));
@@ -79,7 +91,9 @@ void GcodeSuite::M3_M4(const bool is_M4) {
79 91
  * M5 - Cutter OFF
80 92
  */
81 93
 void GcodeSuite::M5() {
82
-  planner.synchronize();
94
+  #if ENABLED(SPINDLE_FEATURE)
95
+    planner.synchronize();
96
+  #endif
83 97
   cutter.set_enabled(false);
84 98
 }
85 99
 

+ 1
- 1
Marlin/src/lcd/menu/menu_spindle_laser.cpp View File

@@ -38,7 +38,7 @@
38 38
     BACK_ITEM(MSG_MAIN);
39 39
     if (cutter.enabled()) {
40 40
       #if ENABLED(SPINDLE_LASER_PWM)
41
-        EDIT_ITEM(CUTTER_MENU_TYPE, MSG_CUTTER(POWER), &cutter.power, SPEED_POWER_MIN, SPEED_POWER_MAX, cutter.update_output);
41
+        EDIT_ITEM(CUTTER_MENU_TYPE, MSG_CUTTER(POWER), &cutter.power, SPEED_POWER_MIN, SPEED_POWER_MAX);
42 42
       #endif
43 43
       ACTION_ITEM(MSG_CUTTER(OFF), cutter.disable);
44 44
     }

+ 30
- 2
Marlin/src/module/planner.cpp View File

@@ -100,6 +100,10 @@
100 100
   #include "../feature/power_loss_recovery.h"
101 101
 #endif
102 102
 
103
+#if HAS_CUTTER
104
+  #include "../feature/spindle_laser.h"
105
+#endif
106
+
103 107
 // Delay for delivery of first block to the stepper ISR, if the queue contains 2 or
104 108
 // fewer movements. The delay is measured in milliseconds, and must be less than 250ms
105 109
 #define BLOCK_DELAY_FOR_1ST_MOVE 100
@@ -1220,6 +1224,11 @@ void Planner::check_axes_activity() {
1220 1224
     #endif
1221 1225
   }
1222 1226
   else {
1227
+
1228
+    #if HAS_CUTTER
1229
+      cutter.refresh();
1230
+    #endif
1231
+
1223 1232
     #if FAN_COUNT > 0
1224 1233
       FANS_LOOP(i)
1225 1234
         tail_fan_speed[i] = thermalManager.scaledFanSpeed(i);
@@ -1235,6 +1244,9 @@ void Planner::check_axes_activity() {
1235 1244
     #endif
1236 1245
   }
1237 1246
 
1247
+  //
1248
+  // Disable inactive axes
1249
+  //
1238 1250
   #if ENABLED(DISABLE_X)
1239 1251
     if (!axis_active.x) disable_X();
1240 1252
   #endif
@@ -1248,6 +1260,9 @@ void Planner::check_axes_activity() {
1248 1260
     if (!axis_active.e) disable_e_steppers();
1249 1261
   #endif
1250 1262
 
1263
+  //
1264
+  // Update Fan speeds
1265
+  //
1251 1266
   #if FAN_COUNT > 0
1252 1267
 
1253 1268
     #if FAN_KICKSTART_TIME > 0
@@ -1841,6 +1856,10 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
1841 1856
     MIXER_POPULATE_BLOCK();
1842 1857
   #endif
1843 1858
 
1859
+  #if HAS_CUTTER
1860
+    block->cutter_power = cutter.power;
1861
+  #endif
1862
+
1844 1863
   #if FAN_COUNT > 0
1845 1864
     FANS_LOOP(i) block->fan_speed[i] = thermalManager.fan_speed[i];
1846 1865
   #endif
@@ -2354,13 +2373,21 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
2354 2373
 
2355 2374
   #endif
2356 2375
 
2376
+  #ifdef USE_CACHED_SQRT
2377
+    #define CACHED_SQRT(N, V) \
2378
+      static float saved_V, N; \
2379
+      if (V != saved_V) { N = SQRT(V); saved_V = V; }
2380
+  #else
2381
+    #define CACHED_SQRT(N, V) const float N = SQRT(V)
2382
+  #endif
2383
+
2357 2384
   #if HAS_CLASSIC_JERK
2358 2385
 
2359 2386
     /**
2360 2387
      * Adapted from Průša MKS firmware
2361 2388
      * https://github.com/prusa3d/Prusa-Firmware
2362 2389
      */
2363
-    const float nominal_speed = SQRT(block->nominal_speed_sqr);
2390
+    CACHED_SQRT(nominal_speed, block->nominal_speed_sqr);
2364 2391
 
2365 2392
     // Exit speed limited by a jerk to full halt of a previous last segment
2366 2393
     static float previous_safe_speed;
@@ -2401,7 +2428,8 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
2401 2428
 
2402 2429
       // The junction velocity will be shared between successive segments. Limit the junction velocity to their minimum.
2403 2430
       // Pick the smaller of the nominal speeds. Higher speed shall not be achieved at the junction during coasting.
2404
-      const float previous_nominal_speed = SQRT(previous_nominal_speed_sqr);
2431
+      CACHED_SQRT(previous_nominal_speed, previous_nominal_speed_sqr);
2432
+
2405 2433
       vmax_junction = _MIN(nominal_speed, previous_nominal_speed);
2406 2434
 
2407 2435
       // Now limit the jerk in all axes.

+ 8
- 0
Marlin/src/module/planner.h View File

@@ -51,6 +51,10 @@
51 51
   #include "../feature/mixing.h"
52 52
 #endif
53 53
 
54
+#if HAS_CUTTER
55
+  #include "../feature/spindle_laser.h"
56
+#endif
57
+
54 58
 // Feedrate for manual moves
55 59
 #ifdef MANUAL_FEEDRATE
56 60
   constexpr xyze_feedrate_t manual_feedrate_mm_m = MANUAL_FEEDRATE;
@@ -145,6 +149,10 @@ typedef struct block_t {
145 149
            final_rate,                      // The minimal rate at exit
146 150
            acceleration_steps_per_s2;       // acceleration steps/sec^2
147 151
 
152
+  #if HAS_CUTTER
153
+    cutter_power_t cutter_power;            // Power level for Spindle, Laser, etc.
154
+  #endif
155
+
148 156
   #if FAN_COUNT > 0
149 157
     uint8_t fan_speed[FAN_COUNT];
150 158
   #endif

+ 4
- 0
Marlin/src/module/stepper.cpp View File

@@ -1667,6 +1667,10 @@ uint32_t Stepper::stepper_block_phase_isr() {
1667 1667
           return interval; // No more queued movements!
1668 1668
       }
1669 1669
 
1670
+      #if HAS_CUTTER
1671
+        cutter.apply_power(current_block->cutter_power);
1672
+      #endif
1673
+
1670 1674
       #if ENABLED(POWER_LOSS_RECOVERY)
1671 1675
         recovery.info.sdpos = current_block->sdpos;
1672 1676
       #endif

Loading…
Cancel
Save