소스 검색

⚡️ PWM for ESP32 I2S expander (#24193)

John Robertson 1 년 전
부모
커밋
ca06c6eab9
No account linked to committer's email address

+ 4
- 1
Marlin/Configuration_adv.h 파일 보기

@@ -3592,7 +3592,10 @@
3592 3592
   #if ENABLED(SPINDLE_LASER_USE_PWM)
3593 3593
     #define SPINDLE_LASER_PWM_INVERT    false  // Set to "true" if the speed/power goes up when you want it to go slower
3594 3594
     #define SPINDLE_LASER_FREQUENCY     2500   // (Hz) Spindle/laser frequency (only on supported HALs: AVR, ESP32, and LPC)
3595
-  #endif
3595
+                                               // ESP32: If SPINDLE_LASER_PWM_PIN is onboard then <=78125Hz. For I2S expander
3596
+                                               //  the frequency determines the PWM resolution. 2500Hz = 0-100, 977Hz = 0-255, ...
3597
+                                               //  (250000 / SPINDLE_LASER_FREQUENCY) = max value.
3598
+#endif
3596 3599
 
3597 3600
   //#define AIR_EVACUATION                     // Cutter Vacuum / Laser Blower motor control with G-codes M10-M11
3598 3601
   #if ENABLED(AIR_EVACUATION)

+ 1
- 1
Marlin/Makefile 파일 보기

@@ -109,7 +109,7 @@ LIQUID_TWI2        ?= 0
109 109
 # This defines if Wire is needed
110 110
 WIRE               ?= 0
111 111
 
112
-# This defines if Tone is needed (i.e SPEAKER is defined in Configuration.h)
112
+# This defines if Tone is needed (i.e., SPEAKER is defined in Configuration.h)
113 113
 # Disabling this (and SPEAKER) saves approximately 350 bytes of memory.
114 114
 TONE               ?= 1
115 115
 

+ 38
- 12
Marlin/src/HAL/ESP32/HAL.cpp 파일 보기

@@ -65,6 +65,7 @@ portMUX_TYPE MarlinHAL::spinlock = portMUX_INITIALIZER_UNLOCKED;
65 65
 // ------------------------
66 66
 
67 67
 uint16_t MarlinHAL::adc_result;
68
+pwm_pin_t MarlinHAL::pwm_pin_data[MAX_EXPANDER_BITS];
68 69
 
69 70
 // ------------------------
70 71
 // Private Variables
@@ -330,21 +331,46 @@ int8_t get_pwm_channel(const pin_t pin, const uint32_t freq, const uint16_t res)
330 331
 }
331 332
 
332 333
 void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=_BV(PWM_RESOLUTION)-1*/, const bool invert/*=false*/) {
333
-  const int8_t cid = get_pwm_channel(pin, PWM_FREQUENCY, PWM_RESOLUTION);
334
-  if (cid >= 0) {
335
-    uint32_t duty = map(invert ? v_size - v : v, 0, v_size, 0, _BV(PWM_RESOLUTION)-1);
336
-    ledcWrite(cid, duty);
337
-  }
334
+  #if ENABLED(I2S_STEPPER_STREAM)
335
+    if (pin > 127) {
336
+      const uint8_t pinlo = pin & 0x7F;
337
+      pwm_pin_t &pindata = pwm_pin_data[pinlo];
338
+      const uint32_t duty = map(invert ? v_size - v : v, 0, v_size, 0, pindata.pwm_cycle_ticks);
339
+      if (duty == 0 || duty == pindata.pwm_cycle_ticks) { // max or min (i.e., on/off)
340
+        pindata.pwm_duty_ticks = 0;  // turn off PWM for this pin
341
+        duty ? SBI32(i2s_port_data, pinlo) : CBI32(i2s_port_data, pinlo); // set pin level
342
+      }
343
+      else
344
+        pindata.pwm_duty_ticks = duty; // PWM duty count = # of 4µs ticks per full PWM cycle
345
+    }
346
+    else
347
+  #endif
348
+    {
349
+      const int8_t cid = get_pwm_channel(pin, PWM_FREQUENCY, PWM_RESOLUTION);
350
+      if (cid >= 0) {
351
+        const uint32_t duty = map(invert ? v_size - v : v, 0, v_size, 0, _BV(PWM_RESOLUTION)-1);
352
+        ledcWrite(cid, duty);
353
+      }
354
+    }
338 355
 }
339 356
 
340 357
 int8_t MarlinHAL::set_pwm_frequency(const pin_t pin, const uint32_t f_desired) {
341
-  const int8_t cid = channel_for_pin(pin);
342
-  if (cid >= 0) {
343
-    if (f_desired == ledcReadFreq(cid)) return cid; // no freq change
344
-    ledcDetachPin(chan_pin[cid]);
345
-    chan_pin[cid] = 0;              // remove old freq channel
346
-  }
347
-  return get_pwm_channel(pin, f_desired, PWM_RESOLUTION); // try for new one
358
+  #if ENABLED(I2S_STEPPER_STREAM)
359
+    if (pin > 127) {
360
+      pwm_pin_data[pin & 0x7F].pwm_cycle_ticks = 1000000UL / f_desired / 4; // # of 4µs ticks per full PWM cycle
361
+      return 0;
362
+    }
363
+    else
364
+  #endif
365
+    {
366
+      const int8_t cid = channel_for_pin(pin);
367
+      if (cid >= 0) {
368
+        if (f_desired == ledcReadFreq(cid)) return cid; // no freq change
369
+        ledcDetachPin(chan_pin[cid]);
370
+        chan_pin[cid] = 0;              // remove old freq channel
371
+      }
372
+      return get_pwm_channel(pin, f_desired, PWM_RESOLUTION); // try for new one
373
+    }
348 374
 }
349 375
 
350 376
 // use hardware PWM if avail, if not then ISR

+ 11
- 0
Marlin/src/HAL/ESP32/HAL.h 파일 보기

@@ -68,6 +68,9 @@
68 68
 #define PWM_RESOLUTION   10u   // Default PWM bit resolution
69 69
 #define CHANNEL_MAX_NUM  15u   // max PWM channel # to allocate (7 to only use low speed, 15 to use low & high)
70 70
 #define MAX_PWM_IOPIN    33u   // hardware pwm pins < 34
71
+#ifndef MAX_EXPANDER_BITS
72
+  #define MAX_EXPANDER_BITS 32 // I2S expander bit width (max 32)
73
+#endif
71 74
 
72 75
 // ------------------------
73 76
 // Types
@@ -76,6 +79,12 @@
76 79
 typedef double isr_float_t;   // FPU ops are used for single-precision, so use double for ISRs.
77 80
 typedef int16_t pin_t;
78 81
 
82
+typedef struct pwm_pin {
83
+  uint32_t pwm_cycle_ticks = 1000000UL / (PWM_FREQUENCY) / 4; // # ticks per pwm cycle
84
+  uint32_t pwm_tick_count = 0;  // current tick count
85
+  uint32_t pwm_duty_ticks = 0;  // # of ticks for current duty cycle
86
+} pwm_pin_t;
87
+
79 88
 class Servo;
80 89
 typedef Servo hal_servo_t;
81 90
 
@@ -197,6 +206,8 @@ public:
197 206
   // Free SRAM
198 207
   static int freeMemory();
199 208
 
209
+  static pwm_pin_t pwm_pin_data[MAX_EXPANDER_BITS];
210
+
200 211
   //
201 212
   // ADC Methods
202 213
   //

+ 20
- 0
Marlin/src/HAL/ESP32/i2s.cpp 파일 보기

@@ -337,6 +337,26 @@ uint8_t i2s_state(uint8_t pin) {
337 337
 }
338 338
 
339 339
 void i2s_push_sample() {
340
+  // Every 4µs (when space in DMA buffer) toggle each expander PWM output using
341
+  // the current duty cycle/frequency so they sync with any steps (once
342
+  // through the DMA/FIFO buffers).  PWM signal inversion handled by other functions
343
+  LOOP_L_N(p, MAX_EXPANDER_BITS) {
344
+    if (hal.pwm_pin_data[p].pwm_duty_ticks > 0) { // pin has active pwm?
345
+      if (hal.pwm_pin_data[p].pwm_tick_count == 0) {
346
+        if (TEST32(i2s_port_data, p)) {  // hi->lo
347
+          CBI32(i2s_port_data, p);
348
+          hal.pwm_pin_data[p].pwm_tick_count = hal.pwm_pin_data[p].pwm_cycle_ticks - hal.pwm_pin_data[p].pwm_duty_ticks;
349
+        }
350
+        else { // lo->hi
351
+          SBI32(i2s_port_data, p);
352
+          hal.pwm_pin_data[p].pwm_tick_count = hal.pwm_pin_data[p].pwm_duty_ticks;
353
+        }
354
+      }
355
+      else
356
+        hal.pwm_pin_data[p].pwm_tick_count--;
357
+    }
358
+  }
359
+
340 360
   dma.current[dma.rw_pos++] = i2s_port_data;
341 361
 }
342 362
 

+ 7
- 0
Marlin/src/HAL/ESP32/inc/Conditionals_adv.h 파일 보기

@@ -20,3 +20,10 @@
20 20
  *
21 21
  */
22 22
 #pragma once
23
+
24
+//
25
+// Board-specific options need to be defined before HAL.h
26
+//
27
+#if MB(MKS_TINYBEE)
28
+  #define MAX_EXPANDER_BITS 24  // TinyBee has 3 x HC595
29
+#endif

+ 4
- 0
Marlin/src/HAL/ESP32/inc/SanityCheck.h 파일 보기

@@ -48,3 +48,7 @@
48 48
 #if USING_PULLDOWNS
49 49
   #error "PULLDOWN pin mode is not available on ESP32 boards."
50 50
 #endif
51
+
52
+#if BOTH(I2S_STEPPER_STREAM, LIN_ADVANCE)
53
+  #error "I2S stream is currently incompatible with LIN_ADVANCE."
54
+#endif

+ 1
- 3
Marlin/src/module/stepper.cpp 파일 보기

@@ -1898,9 +1898,7 @@ void Stepper::pulse_phase_isr() {
1898 1898
       #endif
1899 1899
     #endif
1900 1900
 
1901
-    #if ENABLED(I2S_STEPPER_STREAM)
1902
-      i2s_push_sample();
1903
-    #endif
1901
+    TERN_(I2S_STEPPER_STREAM, i2s_push_sample());
1904 1902
 
1905 1903
     // TODO: need to deal with MINIMUM_STEPPER_PULSE over i2s
1906 1904
     #if ISR_MULTI_STEPS

+ 2
- 7
Marlin/src/pins/esp32/pins_E4D.h 파일 보기

@@ -41,18 +41,13 @@
41 41
 #define DEFAULT_MACHINE_NAME  BOARD_INFO_NAME
42 42
 
43 43
 //
44
-// Disable I2S stepper stream
45
-//
46
-#undef I2S_STEPPER_STREAM
47
-
48
-//
49 44
 // Redefine I2S for ESP32
50 45
 //
51 46
 #undef I2S_WS
52
-#define I2S_WS                                23
53 47
 #undef I2S_BCK
54
-#define I2S_BCK                               22
55 48
 #undef I2S_DATA
49
+#define I2S_WS                                23
50
+#define I2S_BCK                               22
56 51
 #define I2S_DATA                              21
57 52
 
58 53
 //

+ 5
- 3
Marlin/src/pins/esp32/pins_ENWI_ESPNP.h 파일 보기

@@ -35,9 +35,11 @@
35 35
 // I2S (steppers & other output-only pins)
36 36
 //
37 37
 #define I2S_STEPPER_STREAM
38
-#define I2S_WS                                17
39
-#define I2S_BCK                               22
40
-#define I2S_DATA                              21
38
+#if ENABLED(I2S_STEPPER_STREAM)
39
+  #define I2S_WS                              17
40
+  #define I2S_BCK                             22
41
+  #define I2S_DATA                            21
42
+#endif
41 43
 
42 44
 //
43 45
 // Servos

+ 5
- 3
Marlin/src/pins/esp32/pins_ESP32.h 파일 보기

@@ -33,9 +33,11 @@
33 33
 // I2S (steppers & other output-only pins)
34 34
 //
35 35
 #define I2S_STEPPER_STREAM
36
-#define I2S_WS                                25
37
-#define I2S_BCK                               26
38
-#define I2S_DATA                              27
36
+#if ENABLED(I2S_STEPPER_STREAM)
37
+  #define I2S_WS                              25
38
+  #define I2S_BCK                             26
39
+  #define I2S_DATA                            27
40
+#endif
39 41
 
40 42
 //
41 43
 // Limit Switches

+ 0
- 8
Marlin/src/pins/esp32/pins_ESPA_common.h 파일 보기

@@ -33,14 +33,6 @@
33 33
 #endif
34 34
 
35 35
 //
36
-// Disable I2S stepper stream, by default
37
-//
38
-#undef I2S_STEPPER_STREAM
39
-#undef I2S_WS
40
-#undef I2S_BCK
41
-#undef I2S_DATA
42
-
43
-//
44 36
 // Limit Switches
45 37
 //
46 38
 #define X_STOP_PIN                            34

+ 2
- 3
Marlin/src/pins/esp32/pins_MKS_TINYBEE.h 파일 보기

@@ -40,6 +40,8 @@
40 40
 #define BOARD_WEBSITE_URL    "https://github.com/makerbase-mks"
41 41
 #define DEFAULT_MACHINE_NAME BOARD_INFO_NAME
42 42
 
43
+// MAX_EXPANDER_BITS is defined for MKS TinyBee in HAL/ESP32/inc/Conditionals_adv.h
44
+
43 45
 //
44 46
 // Servos
45 47
 //
@@ -61,9 +63,6 @@
61 63
   #define I2S_WS                              26
62 64
   #define I2S_BCK                             25
63 65
   #define I2S_DATA                            27
64
-  #if ENABLED(LIN_ADVANCE)
65
-    #error "I2S stream is currently incompatible with LIN_ADVANCE."
66
-  #endif
67 66
 #endif
68 67
 
69 68
 //

+ 4
- 5
Marlin/src/pins/esp32/pins_MRR_ESPE.h 파일 보기

@@ -52,11 +52,10 @@
52 52
 // Enable I2S stepper stream
53 53
 //
54 54
 #define I2S_STEPPER_STREAM
55
-#define I2S_WS                                26
56
-#define I2S_BCK                               25
57
-#define I2S_DATA                              27
58
-#if ENABLED(LIN_ADVANCE)
59
-  #error "I2S stream is currently incompatible with LIN_ADVANCE."
55
+#if ENABLED(I2S_STEPPER_STREAM)
56
+  #define I2S_WS                              26
57
+  #define I2S_BCK                             25
58
+  #define I2S_DATA                            27
60 59
 #endif
61 60
 
62 61
 //

Loading…
취소
저장