⚡️ PWM for ESP32 I2S expander (#24193)
This commit is contained in:
parent
7677368aaf
commit
c34dd64469
@ -3592,6 +3592,9 @@
|
|||||||
#if ENABLED(SPINDLE_LASER_USE_PWM)
|
#if ENABLED(SPINDLE_LASER_USE_PWM)
|
||||||
#define SPINDLE_LASER_PWM_INVERT false // Set to "true" if the speed/power goes up when you want it to go slower
|
#define SPINDLE_LASER_PWM_INVERT false // Set to "true" if the speed/power goes up when you want it to go slower
|
||||||
#define SPINDLE_LASER_FREQUENCY 2500 // (Hz) Spindle/laser frequency (only on supported HALs: AVR, ESP32, and LPC)
|
#define SPINDLE_LASER_FREQUENCY 2500 // (Hz) Spindle/laser frequency (only on supported HALs: AVR, ESP32, and LPC)
|
||||||
|
// ESP32: If SPINDLE_LASER_PWM_PIN is onboard then <=78125Hz. For I2S expander
|
||||||
|
// the frequency determines the PWM resolution. 2500Hz = 0-100, 977Hz = 0-255, ...
|
||||||
|
// (250000 / SPINDLE_LASER_FREQUENCY) = max value.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//#define AIR_EVACUATION // Cutter Vacuum / Laser Blower motor control with G-codes M10-M11
|
//#define AIR_EVACUATION // Cutter Vacuum / Laser Blower motor control with G-codes M10-M11
|
||||||
|
@ -109,7 +109,7 @@ LIQUID_TWI2 ?= 0
|
|||||||
# This defines if Wire is needed
|
# This defines if Wire is needed
|
||||||
WIRE ?= 0
|
WIRE ?= 0
|
||||||
|
|
||||||
# This defines if Tone is needed (i.e SPEAKER is defined in Configuration.h)
|
# This defines if Tone is needed (i.e., SPEAKER is defined in Configuration.h)
|
||||||
# Disabling this (and SPEAKER) saves approximately 350 bytes of memory.
|
# Disabling this (and SPEAKER) saves approximately 350 bytes of memory.
|
||||||
TONE ?= 1
|
TONE ?= 1
|
||||||
|
|
||||||
|
@ -65,6 +65,7 @@ portMUX_TYPE MarlinHAL::spinlock = portMUX_INITIALIZER_UNLOCKED;
|
|||||||
// ------------------------
|
// ------------------------
|
||||||
|
|
||||||
uint16_t MarlinHAL::adc_result;
|
uint16_t MarlinHAL::adc_result;
|
||||||
|
pwm_pin_t MarlinHAL::pwm_pin_data[MAX_EXPANDER_BITS];
|
||||||
|
|
||||||
// ------------------------
|
// ------------------------
|
||||||
// Private Variables
|
// Private Variables
|
||||||
@ -330,14 +331,38 @@ int8_t get_pwm_channel(const pin_t pin, const uint32_t freq, const uint16_t res)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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*/) {
|
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*/) {
|
||||||
|
#if ENABLED(I2S_STEPPER_STREAM)
|
||||||
|
if (pin > 127) {
|
||||||
|
const uint8_t pinlo = pin & 0x7F;
|
||||||
|
pwm_pin_t &pindata = pwm_pin_data[pinlo];
|
||||||
|
const uint32_t duty = map(invert ? v_size - v : v, 0, v_size, 0, pindata.pwm_cycle_ticks);
|
||||||
|
if (duty == 0 || duty == pindata.pwm_cycle_ticks) { // max or min (i.e., on/off)
|
||||||
|
pindata.pwm_duty_ticks = 0; // turn off PWM for this pin
|
||||||
|
duty ? SBI32(i2s_port_data, pinlo) : CBI32(i2s_port_data, pinlo); // set pin level
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pindata.pwm_duty_ticks = duty; // PWM duty count = # of 4µs ticks per full PWM cycle
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
const int8_t cid = get_pwm_channel(pin, PWM_FREQUENCY, PWM_RESOLUTION);
|
const int8_t cid = get_pwm_channel(pin, PWM_FREQUENCY, PWM_RESOLUTION);
|
||||||
if (cid >= 0) {
|
if (cid >= 0) {
|
||||||
uint32_t duty = map(invert ? v_size - v : v, 0, v_size, 0, _BV(PWM_RESOLUTION)-1);
|
const uint32_t duty = map(invert ? v_size - v : v, 0, v_size, 0, _BV(PWM_RESOLUTION)-1);
|
||||||
ledcWrite(cid, duty);
|
ledcWrite(cid, duty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int8_t MarlinHAL::set_pwm_frequency(const pin_t pin, const uint32_t f_desired) {
|
int8_t MarlinHAL::set_pwm_frequency(const pin_t pin, const uint32_t f_desired) {
|
||||||
|
#if ENABLED(I2S_STEPPER_STREAM)
|
||||||
|
if (pin > 127) {
|
||||||
|
pwm_pin_data[pin & 0x7F].pwm_cycle_ticks = 1000000UL / f_desired / 4; // # of 4µs ticks per full PWM cycle
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
const int8_t cid = channel_for_pin(pin);
|
const int8_t cid = channel_for_pin(pin);
|
||||||
if (cid >= 0) {
|
if (cid >= 0) {
|
||||||
if (f_desired == ledcReadFreq(cid)) return cid; // no freq change
|
if (f_desired == ledcReadFreq(cid)) return cid; // no freq change
|
||||||
@ -346,6 +371,7 @@ int8_t MarlinHAL::set_pwm_frequency(const pin_t pin, const uint32_t f_desired) {
|
|||||||
}
|
}
|
||||||
return get_pwm_channel(pin, f_desired, PWM_RESOLUTION); // try for new one
|
return get_pwm_channel(pin, f_desired, PWM_RESOLUTION); // try for new one
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// use hardware PWM if avail, if not then ISR
|
// use hardware PWM if avail, if not then ISR
|
||||||
void analogWrite(const pin_t pin, const uint16_t value, const uint32_t freq/*=PWM_FREQUENCY*/, const uint16_t res/*=8*/) { // always 8 bit resolution!
|
void analogWrite(const pin_t pin, const uint16_t value, const uint32_t freq/*=PWM_FREQUENCY*/, const uint16_t res/*=8*/) { // always 8 bit resolution!
|
||||||
|
@ -68,6 +68,9 @@
|
|||||||
#define PWM_RESOLUTION 10u // Default PWM bit resolution
|
#define PWM_RESOLUTION 10u // Default PWM bit resolution
|
||||||
#define CHANNEL_MAX_NUM 15u // max PWM channel # to allocate (7 to only use low speed, 15 to use low & high)
|
#define CHANNEL_MAX_NUM 15u // max PWM channel # to allocate (7 to only use low speed, 15 to use low & high)
|
||||||
#define MAX_PWM_IOPIN 33u // hardware pwm pins < 34
|
#define MAX_PWM_IOPIN 33u // hardware pwm pins < 34
|
||||||
|
#ifndef MAX_EXPANDER_BITS
|
||||||
|
#define MAX_EXPANDER_BITS 32 // I2S expander bit width (max 32)
|
||||||
|
#endif
|
||||||
|
|
||||||
// ------------------------
|
// ------------------------
|
||||||
// Types
|
// Types
|
||||||
@ -76,6 +79,12 @@
|
|||||||
typedef double isr_float_t; // FPU ops are used for single-precision, so use double for ISRs.
|
typedef double isr_float_t; // FPU ops are used for single-precision, so use double for ISRs.
|
||||||
typedef int16_t pin_t;
|
typedef int16_t pin_t;
|
||||||
|
|
||||||
|
typedef struct pwm_pin {
|
||||||
|
uint32_t pwm_cycle_ticks = 1000000UL / (PWM_FREQUENCY) / 4; // # ticks per pwm cycle
|
||||||
|
uint32_t pwm_tick_count = 0; // current tick count
|
||||||
|
uint32_t pwm_duty_ticks = 0; // # of ticks for current duty cycle
|
||||||
|
} pwm_pin_t;
|
||||||
|
|
||||||
class Servo;
|
class Servo;
|
||||||
typedef Servo hal_servo_t;
|
typedef Servo hal_servo_t;
|
||||||
|
|
||||||
@ -197,6 +206,8 @@ public:
|
|||||||
// Free SRAM
|
// Free SRAM
|
||||||
static int freeMemory();
|
static int freeMemory();
|
||||||
|
|
||||||
|
static pwm_pin_t pwm_pin_data[MAX_EXPANDER_BITS];
|
||||||
|
|
||||||
//
|
//
|
||||||
// ADC Methods
|
// ADC Methods
|
||||||
//
|
//
|
||||||
|
@ -337,6 +337,26 @@ uint8_t i2s_state(uint8_t pin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void i2s_push_sample() {
|
void i2s_push_sample() {
|
||||||
|
// Every 4µs (when space in DMA buffer) toggle each expander PWM output using
|
||||||
|
// the current duty cycle/frequency so they sync with any steps (once
|
||||||
|
// through the DMA/FIFO buffers). PWM signal inversion handled by other functions
|
||||||
|
LOOP_L_N(p, MAX_EXPANDER_BITS) {
|
||||||
|
if (hal.pwm_pin_data[p].pwm_duty_ticks > 0) { // pin has active pwm?
|
||||||
|
if (hal.pwm_pin_data[p].pwm_tick_count == 0) {
|
||||||
|
if (TEST32(i2s_port_data, p)) { // hi->lo
|
||||||
|
CBI32(i2s_port_data, p);
|
||||||
|
hal.pwm_pin_data[p].pwm_tick_count = hal.pwm_pin_data[p].pwm_cycle_ticks - hal.pwm_pin_data[p].pwm_duty_ticks;
|
||||||
|
}
|
||||||
|
else { // lo->hi
|
||||||
|
SBI32(i2s_port_data, p);
|
||||||
|
hal.pwm_pin_data[p].pwm_tick_count = hal.pwm_pin_data[p].pwm_duty_ticks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
hal.pwm_pin_data[p].pwm_tick_count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dma.current[dma.rw_pos++] = i2s_port_data;
|
dma.current[dma.rw_pos++] = i2s_port_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,3 +20,10 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
//
|
||||||
|
// Board-specific options need to be defined before HAL.h
|
||||||
|
//
|
||||||
|
#if MB(MKS_TINYBEE)
|
||||||
|
#define MAX_EXPANDER_BITS 24 // TinyBee has 3 x HC595
|
||||||
|
#endif
|
||||||
|
@ -48,3 +48,7 @@
|
|||||||
#if USING_PULLDOWNS
|
#if USING_PULLDOWNS
|
||||||
#error "PULLDOWN pin mode is not available on ESP32 boards."
|
#error "PULLDOWN pin mode is not available on ESP32 boards."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if BOTH(I2S_STEPPER_STREAM, LIN_ADVANCE)
|
||||||
|
#error "I2S stream is currently incompatible with LIN_ADVANCE."
|
||||||
|
#endif
|
||||||
|
@ -1898,9 +1898,7 @@ void Stepper::pulse_phase_isr() {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLED(I2S_STEPPER_STREAM)
|
TERN_(I2S_STEPPER_STREAM, i2s_push_sample());
|
||||||
i2s_push_sample();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// TODO: need to deal with MINIMUM_STEPPER_PULSE over i2s
|
// TODO: need to deal with MINIMUM_STEPPER_PULSE over i2s
|
||||||
#if ISR_MULTI_STEPS
|
#if ISR_MULTI_STEPS
|
||||||
|
@ -40,19 +40,14 @@
|
|||||||
#define BOARD_WEBSITE_URL "github.com/Exilaus/E4d@box"
|
#define BOARD_WEBSITE_URL "github.com/Exilaus/E4d@box"
|
||||||
#define DEFAULT_MACHINE_NAME BOARD_INFO_NAME
|
#define DEFAULT_MACHINE_NAME BOARD_INFO_NAME
|
||||||
|
|
||||||
//
|
|
||||||
// Disable I2S stepper stream
|
|
||||||
//
|
|
||||||
#undef I2S_STEPPER_STREAM
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Redefine I2S for ESP32
|
// Redefine I2S for ESP32
|
||||||
//
|
//
|
||||||
#undef I2S_WS
|
#undef I2S_WS
|
||||||
#define I2S_WS 23
|
|
||||||
#undef I2S_BCK
|
#undef I2S_BCK
|
||||||
#define I2S_BCK 22
|
|
||||||
#undef I2S_DATA
|
#undef I2S_DATA
|
||||||
|
#define I2S_WS 23
|
||||||
|
#define I2S_BCK 22
|
||||||
#define I2S_DATA 21
|
#define I2S_DATA 21
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -35,9 +35,11 @@
|
|||||||
// I2S (steppers & other output-only pins)
|
// I2S (steppers & other output-only pins)
|
||||||
//
|
//
|
||||||
#define I2S_STEPPER_STREAM
|
#define I2S_STEPPER_STREAM
|
||||||
|
#if ENABLED(I2S_STEPPER_STREAM)
|
||||||
#define I2S_WS 17
|
#define I2S_WS 17
|
||||||
#define I2S_BCK 22
|
#define I2S_BCK 22
|
||||||
#define I2S_DATA 21
|
#define I2S_DATA 21
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// Servos
|
// Servos
|
||||||
|
@ -33,9 +33,11 @@
|
|||||||
// I2S (steppers & other output-only pins)
|
// I2S (steppers & other output-only pins)
|
||||||
//
|
//
|
||||||
#define I2S_STEPPER_STREAM
|
#define I2S_STEPPER_STREAM
|
||||||
|
#if ENABLED(I2S_STEPPER_STREAM)
|
||||||
#define I2S_WS 25
|
#define I2S_WS 25
|
||||||
#define I2S_BCK 26
|
#define I2S_BCK 26
|
||||||
#define I2S_DATA 27
|
#define I2S_DATA 27
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// Limit Switches
|
// Limit Switches
|
||||||
|
@ -32,14 +32,6 @@
|
|||||||
#define DEFAULT_MACHINE_NAME BOARD_INFO_NAME
|
#define DEFAULT_MACHINE_NAME BOARD_INFO_NAME
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//
|
|
||||||
// Disable I2S stepper stream, by default
|
|
||||||
//
|
|
||||||
#undef I2S_STEPPER_STREAM
|
|
||||||
#undef I2S_WS
|
|
||||||
#undef I2S_BCK
|
|
||||||
#undef I2S_DATA
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Limit Switches
|
// Limit Switches
|
||||||
//
|
//
|
||||||
|
@ -40,6 +40,8 @@
|
|||||||
#define BOARD_WEBSITE_URL "https://github.com/makerbase-mks"
|
#define BOARD_WEBSITE_URL "https://github.com/makerbase-mks"
|
||||||
#define DEFAULT_MACHINE_NAME BOARD_INFO_NAME
|
#define DEFAULT_MACHINE_NAME BOARD_INFO_NAME
|
||||||
|
|
||||||
|
// MAX_EXPANDER_BITS is defined for MKS TinyBee in HAL/ESP32/inc/Conditionals_adv.h
|
||||||
|
|
||||||
//
|
//
|
||||||
// Servos
|
// Servos
|
||||||
//
|
//
|
||||||
@ -61,9 +63,6 @@
|
|||||||
#define I2S_WS 26
|
#define I2S_WS 26
|
||||||
#define I2S_BCK 25
|
#define I2S_BCK 25
|
||||||
#define I2S_DATA 27
|
#define I2S_DATA 27
|
||||||
#if ENABLED(LIN_ADVANCE)
|
|
||||||
#error "I2S stream is currently incompatible with LIN_ADVANCE."
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -52,11 +52,10 @@
|
|||||||
// Enable I2S stepper stream
|
// Enable I2S stepper stream
|
||||||
//
|
//
|
||||||
#define I2S_STEPPER_STREAM
|
#define I2S_STEPPER_STREAM
|
||||||
|
#if ENABLED(I2S_STEPPER_STREAM)
|
||||||
#define I2S_WS 26
|
#define I2S_WS 26
|
||||||
#define I2S_BCK 25
|
#define I2S_BCK 25
|
||||||
#define I2S_DATA 27
|
#define I2S_DATA 27
|
||||||
#if ENABLED(LIN_ADVANCE)
|
|
||||||
#error "I2S stream is currently incompatible with LIN_ADVANCE."
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
|
Loading…
Reference in New Issue
Block a user