From 221900d201d6ae30d4d8ec7ef209f5556ea745f9 Mon Sep 17 00:00:00 2001 From: Mitch Bradley Date: Tue, 22 Jun 2021 08:53:48 -1000 Subject: [PATCH] Fixed BESC spindle speed handling --- Grbl_Esp32/data/spindles.yaml | 2 +- Grbl_Esp32/src/Spindles/BESCSpindle.cpp | 56 +++++++++++++++++++------ Grbl_Esp32/src/Spindles/BESCSpindle.h | 10 ++++- 3 files changed, 53 insertions(+), 15 deletions(-) diff --git a/Grbl_Esp32/data/spindles.yaml b/Grbl_Esp32/data/spindles.yaml index d09885c1..21572037 100644 --- a/Grbl_Esp32/data/spindles.yaml +++ b/Grbl_Esp32/data/spindles.yaml @@ -99,7 +99,7 @@ PWM: BESC: min_pulse_us: 950 max_pulse_us: 2050 - speeds: 0=0% 30000=100% + # speeds: 0=0% 0=20% 2000=20% 5000=40% 10000=100% output_pin: gpio.4 enable_pin: gpio.10 tool: 40 diff --git a/Grbl_Esp32/src/Spindles/BESCSpindle.cpp b/Grbl_Esp32/src/Spindles/BESCSpindle.cpp index 047ef6b1..1c22bec4 100644 --- a/Grbl_Esp32/src/Spindles/BESCSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/BESCSpindle.cpp @@ -31,6 +31,7 @@ */ #include "BESCSpindle.h" +#include "soc/ledc_struct.h" namespace Spindles { void BESC::init() { @@ -53,30 +54,59 @@ namespace Spindles { _enable_pin.setAttr(Pin::Attr::Output); + // BESC PWM typically represents 0 speed as a 1ms pulse and max speed as a 2ms pulse + // 1000000 is us/sec - const uint32_t besc_pulse_period_us = 1000000 / besc_pwm_freq; + const uint32_t pulse_period_us = 1000000 / besc_pwm_freq; - float _min_pulse_percent = 100.0 * _min_pulse_us / besc_pulse_period_us; - float _max_pulse_percent = 100.0 * _max_pulse_us / besc_pulse_period_us; + // Calculate the pulse length offset and scaler in counts of the LEDC controller + _min_pulse_counts = _min_pulse_us << _pwm_precision / pulse_period_us; + _pulse_span_counts = (_max_pulse_us - _min_pulse_us) << _pwm_precision / pulse_period_us; - uint32_t max_speed = 20000; // Default value if none given in speeds: - if (_speeds.size() != 0) { - log_info("Overriding PWM speed map for BESC"); - // Extract the maximum speed from the provide speed map - max_speed = maxSpeed(); + if (_speeds.size() == 0) { + shelfSpeeds(4000, 20000); } - // BESC PWM typically represents 0 speed as a 1ms pulse and max speed as a 2ms pulse - _speeds.clear(); - _speeds.push_back({ 0, _min_pulse_percent }); - _speeds.push_back({ max_speed, _max_pulse_percent }); - + // We set the dev_speed scale in the speed map to the full PWM period (64K) + // Then, in set_output, we map the dev_speed range of 0..64K to the pulse + // length range of ~1ms .. 2ms setupSpeeds(_pwm_period); stop(); config_message(); } + void IRAM_ATTR BESC::set_output(uint32_t duty) { + if (_output_pin.undefined()) { + return; + } + + // to prevent excessive calls to ledcWrite, make sure duty has changed + if (duty == _current_pwm_duty) { + return; + } + + _current_pwm_duty = duty; + + // if (_invert_pwm) { + // duty = (1 << _pwm_precision) - duty; + // } + // This maps the dev_speed range of 0..(1<<_pwm_precision) into the pulse length + // where _min_pulse_counts represents off and (_min_pulse_counts + _pulse_span_counts) + // represents full on. Typically the off value is a 1ms pulse length and the + // full on value is a 2ms pulse. + uint32_t pulse_counts = _min_pulse_counts * _pulse_span_counts >> _pwm_precision; + + //ledcWrite(_pwm_chan_num, duty); + + // This was ledcWrite, but this is called from an ISR + // and ledcWrite uses RTOS features not compatible with ISRs + LEDC.channel_group[0].channel[0].duty.duty = pulse_counts << 4; + bool on = !!duty; + LEDC.channel_group[0].channel[0].conf0.sig_out_en = on; + LEDC.channel_group[0].channel[0].conf1.duty_start = on; + } + // prints the startup message of the spindle config void BESC::config_message() { info_all("BESC spindle on Pin:%s Min:%dus Max:%dus Freq:%dHz Res:%dbits", diff --git a/Grbl_Esp32/src/Spindles/BESCSpindle.h b/Grbl_Esp32/src/Spindles/BESCSpindle.h index a7b8f83d..38c0d3dc 100644 --- a/Grbl_Esp32/src/Spindles/BESCSpindle.h +++ b/Grbl_Esp32/src/Spindles/BESCSpindle.h @@ -37,9 +37,15 @@ namespace Spindles { class BESC : public PWM { - protected: + private: + // Fixed const uint32_t besc_pwm_freq = 50; // 50 Hz + // Calculated + uint16_t _pulse_span_counts; // In counts of a 16-bit counter + uint16_t _min_pulse_counts; // In counts of a 16-bit counter + + protected: // Configurable uint32_t _min_pulse_us = 900; // microseconds uint32_t _max_pulse_us = 2200; // microseconds @@ -55,6 +61,8 @@ namespace Spindles { void init() override; void config_message() override; + virtual void set_output(uint32_t duty) override; + // Configuration handlers: void validate() const override { PWM::validate(); }