Browse Source

⚡️ PWM for ESP32 I2S expander (#24193)

John Robertson 3 years ago
parent
commit
ca06c6eab9
No account linked to committer's email address

+ 4
- 1
Marlin/Configuration_adv.h View File

3592
   #if ENABLED(SPINDLE_LASER_USE_PWM)
3592
   #if ENABLED(SPINDLE_LASER_USE_PWM)
3593
     #define SPINDLE_LASER_PWM_INVERT    false  // Set to "true" if the speed/power goes up when you want it to go slower
3593
     #define SPINDLE_LASER_PWM_INVERT    false  // Set to "true" if the speed/power goes up when you want it to go slower
3594
     #define SPINDLE_LASER_FREQUENCY     2500   // (Hz) Spindle/laser frequency (only on supported HALs: AVR, ESP32, and LPC)
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
   //#define AIR_EVACUATION                     // Cutter Vacuum / Laser Blower motor control with G-codes M10-M11
3600
   //#define AIR_EVACUATION                     // Cutter Vacuum / Laser Blower motor control with G-codes M10-M11
3598
   #if ENABLED(AIR_EVACUATION)
3601
   #if ENABLED(AIR_EVACUATION)

+ 1
- 1
Marlin/Makefile View File

109
 # This defines if Wire is needed
109
 # This defines if Wire is needed
110
 WIRE               ?= 0
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
 # Disabling this (and SPEAKER) saves approximately 350 bytes of memory.
113
 # Disabling this (and SPEAKER) saves approximately 350 bytes of memory.
114
 TONE               ?= 1
114
 TONE               ?= 1
115
 
115
 

+ 38
- 12
Marlin/src/HAL/ESP32/HAL.cpp View File

65
 // ------------------------
65
 // ------------------------
66
 
66
 
67
 uint16_t MarlinHAL::adc_result;
67
 uint16_t MarlinHAL::adc_result;
68
+pwm_pin_t MarlinHAL::pwm_pin_data[MAX_EXPANDER_BITS];
68
 
69
 
69
 // ------------------------
70
 // ------------------------
70
 // Private Variables
71
 // Private Variables
330
 }
331
 }
331
 
332
 
332
 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
 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
 int8_t MarlinHAL::set_pwm_frequency(const pin_t pin, const uint32_t f_desired) {
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
 // use hardware PWM if avail, if not then ISR
376
 // use hardware PWM if avail, if not then ISR

+ 11
- 0
Marlin/src/HAL/ESP32/HAL.h View File

68
 #define PWM_RESOLUTION   10u   // Default PWM bit resolution
68
 #define PWM_RESOLUTION   10u   // Default PWM bit resolution
69
 #define CHANNEL_MAX_NUM  15u   // max PWM channel # to allocate (7 to only use low speed, 15 to use low & high)
69
 #define CHANNEL_MAX_NUM  15u   // max PWM channel # to allocate (7 to only use low speed, 15 to use low & high)
70
 #define MAX_PWM_IOPIN    33u   // hardware pwm pins < 34
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
 // Types
76
 // Types
76
 typedef double isr_float_t;   // FPU ops are used for single-precision, so use double for ISRs.
79
 typedef double isr_float_t;   // FPU ops are used for single-precision, so use double for ISRs.
77
 typedef int16_t pin_t;
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
 class Servo;
88
 class Servo;
80
 typedef Servo hal_servo_t;
89
 typedef Servo hal_servo_t;
81
 
90
 
197
   // Free SRAM
206
   // Free SRAM
198
   static int freeMemory();
207
   static int freeMemory();
199
 
208
 
209
+  static pwm_pin_t pwm_pin_data[MAX_EXPANDER_BITS];
210
+
200
   //
211
   //
201
   // ADC Methods
212
   // ADC Methods
202
   //
213
   //

+ 20
- 0
Marlin/src/HAL/ESP32/i2s.cpp View File

337
 }
337
 }
338
 
338
 
339
 void i2s_push_sample() {
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
   dma.current[dma.rw_pos++] = i2s_port_data;
360
   dma.current[dma.rw_pos++] = i2s_port_data;
341
 }
361
 }
342
 
362
 

+ 7
- 0
Marlin/src/HAL/ESP32/inc/Conditionals_adv.h View File

20
  *
20
  *
21
  */
21
  */
22
 #pragma once
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 View File

48
 #if USING_PULLDOWNS
48
 #if USING_PULLDOWNS
49
   #error "PULLDOWN pin mode is not available on ESP32 boards."
49
   #error "PULLDOWN pin mode is not available on ESP32 boards."
50
 #endif
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 View File

1898
       #endif
1898
       #endif
1899
     #endif
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
     // TODO: need to deal with MINIMUM_STEPPER_PULSE over i2s
1903
     // TODO: need to deal with MINIMUM_STEPPER_PULSE over i2s
1906
     #if ISR_MULTI_STEPS
1904
     #if ISR_MULTI_STEPS

+ 2
- 7
Marlin/src/pins/esp32/pins_E4D.h View File

41
 #define DEFAULT_MACHINE_NAME  BOARD_INFO_NAME
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
 // Redefine I2S for ESP32
44
 // Redefine I2S for ESP32
50
 //
45
 //
51
 #undef I2S_WS
46
 #undef I2S_WS
52
-#define I2S_WS                                23
53
 #undef I2S_BCK
47
 #undef I2S_BCK
54
-#define I2S_BCK                               22
55
 #undef I2S_DATA
48
 #undef I2S_DATA
49
+#define I2S_WS                                23
50
+#define I2S_BCK                               22
56
 #define I2S_DATA                              21
51
 #define I2S_DATA                              21
57
 
52
 
58
 //
53
 //

+ 5
- 3
Marlin/src/pins/esp32/pins_ENWI_ESPNP.h View File

35
 // I2S (steppers & other output-only pins)
35
 // I2S (steppers & other output-only pins)
36
 //
36
 //
37
 #define I2S_STEPPER_STREAM
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
 // Servos
45
 // Servos

+ 5
- 3
Marlin/src/pins/esp32/pins_ESP32.h View File

33
 // I2S (steppers & other output-only pins)
33
 // I2S (steppers & other output-only pins)
34
 //
34
 //
35
 #define I2S_STEPPER_STREAM
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
 // Limit Switches
43
 // Limit Switches

+ 0
- 8
Marlin/src/pins/esp32/pins_ESPA_common.h View File

33
 #endif
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
 // Limit Switches
36
 // Limit Switches
45
 //
37
 //
46
 #define X_STOP_PIN                            34
38
 #define X_STOP_PIN                            34

+ 2
- 3
Marlin/src/pins/esp32/pins_MKS_TINYBEE.h View File

40
 #define BOARD_WEBSITE_URL    "https://github.com/makerbase-mks"
40
 #define BOARD_WEBSITE_URL    "https://github.com/makerbase-mks"
41
 #define DEFAULT_MACHINE_NAME BOARD_INFO_NAME
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
 // Servos
46
 // Servos
45
 //
47
 //
61
   #define I2S_WS                              26
63
   #define I2S_WS                              26
62
   #define I2S_BCK                             25
64
   #define I2S_BCK                             25
63
   #define I2S_DATA                            27
65
   #define I2S_DATA                            27
64
-  #if ENABLED(LIN_ADVANCE)
65
-    #error "I2S stream is currently incompatible with LIN_ADVANCE."
66
-  #endif
67
 #endif
66
 #endif
68
 
67
 
69
 //
68
 //

+ 4
- 5
Marlin/src/pins/esp32/pins_MRR_ESPE.h View File

52
 // Enable I2S stepper stream
52
 // Enable I2S stepper stream
53
 //
53
 //
54
 #define I2S_STEPPER_STREAM
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
 #endif
59
 #endif
61
 
60
 
62
 //
61
 //

Loading…
Cancel
Save