diff --git a/Grbl_Esp32/Grbl_Esp32.ino b/Grbl_Esp32/Grbl_Esp32.ino index ca3f0587..9fe7f085 100644 --- a/Grbl_Esp32/Grbl_Esp32.ino +++ b/Grbl_Esp32/Grbl_Esp32.ino @@ -34,7 +34,7 @@ volatile uint8_t sys_rt_exec_accessory_override; // Global realtime executor bi volatile uint8_t sys_rt_exec_debug; #endif -Spindle* spindle; +Spindles::Spindle* spindle; void setup() { #ifdef USE_I2S_OUT @@ -87,7 +87,7 @@ void setup() { if (homing_enable->get()) sys.state = STATE_ALARM; #endif - spindle_select(); + Spindles::Spindle::spindle_select(); #ifdef ENABLE_WIFI wifi_config.begin(); #endif diff --git a/Grbl_Esp32/src/Spindles/10vSpindle.cpp b/Grbl_Esp32/src/Spindles/10vSpindle.cpp index 60691f28..7b872465 100644 --- a/Grbl_Esp32/src/Spindles/10vSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/10vSpindle.cpp @@ -23,143 +23,142 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grbl. If not, see . - - - */ -#include "SpindleClass.h" +#include "10vSpindle.h" -void _10vSpindle ::init() { - get_pins_and_settings(); // these gets the standard PWM settings, but many need to be changed for BESC +namespace Spindles { + void _10vSpindle::init() { + get_pins_and_settings(); // these gets the standard PWM settings, but many need to be changed for BESC - // a couple more pins not inherited from PWM Spindle + // a couple more pins not inherited from PWM Spindle #ifdef SPINDLE_FORWARD_PIN - _forward_pin = SPINDLE_FORWARD_PIN; + _forward_pin = SPINDLE_FORWARD_PIN; #else - _forward_pin = UNDEFINED_PIN; + _forward_pin = UNDEFINED_PIN; #endif #ifdef SPINDLE_REVERSE_PIN - _reverse_pin = SPINDLE_REVERSE_PIN; + _reverse_pin = SPINDLE_REVERSE_PIN; #else - _reverse_pin = UNDEFINED_PIN; + _reverse_pin = UNDEFINED_PIN; #endif - if (_output_pin == UNDEFINED_PIN) { - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: BESC output pin not defined"); - return; // We cannot continue without the output pin + if (_output_pin == UNDEFINED_PIN) { + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: BESC output pin not defined"); + return; // We cannot continue without the output pin + } + + ledcSetup(_spindle_pwm_chan_num, (double)_pwm_freq, _pwm_precision); // setup the channel + ledcAttachPin(_output_pin, _spindle_pwm_chan_num); // attach the PWM to the pin + + pinMode(_enable_pin, OUTPUT); + pinMode(_direction_pin, OUTPUT); + pinMode(_forward_pin, OUTPUT); + pinMode(_reverse_pin, OUTPUT); + + set_rpm(0); + + config_message(); + + is_reversable = true; // these VFDs are always reversable + use_delays = true; } - ledcSetup(_spindle_pwm_chan_num, (double)_pwm_freq, _pwm_precision); // setup the channel - ledcAttachPin(_output_pin, _spindle_pwm_chan_num); // attach the PWM to the pin + // prints the startup message of the spindle config + void _10vSpindle::config_message() { + grbl_msg_sendf(CLIENT_SERIAL, + MSG_LEVEL_INFO, + "0-10V spindle Out:%s Enbl:%s, Dir:%s, Fwd:%s, Rev:%s, Freq:%dHz Res:%dbits", + pinName(_output_pin).c_str(), + pinName(_enable_pin).c_str(), + pinName(_direction_pin).c_str(), + pinName(_forward_pin).c_str(), + pinName(_reverse_pin).c_str(), + _pwm_freq, + _pwm_precision); + } - pinMode(_enable_pin, OUTPUT); - pinMode(_direction_pin, OUTPUT); - pinMode(_forward_pin, OUTPUT); - pinMode(_reverse_pin, OUTPUT); + uint32_t _10vSpindle::set_rpm(uint32_t rpm) { + uint32_t pwm_value; - set_rpm(0); + if (_output_pin == UNDEFINED_PIN) + return rpm; - config_message(); + // apply speed overrides + rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (percent) - is_reversable = true; // these VFDs are always reversable - use_delays = true; -} + // apply limits limits + if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm)) + rpm = _max_rpm; + else if (rpm != 0 && rpm <= _min_rpm) + rpm = _min_rpm; + sys.spindle_speed = rpm; -// prints the startup message of the spindle config -void _10vSpindle ::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, - MSG_LEVEL_INFO, - "0-10V spindle Out:%s Enbl:%s, Dir:%s, Fwd:%s, Rev:%s, Freq:%dHz Res:%dbits", - pinName(_output_pin).c_str(), - pinName(_enable_pin).c_str(), - pinName(_direction_pin).c_str(), - pinName(_forward_pin).c_str(), - pinName(_reverse_pin).c_str(), - _pwm_freq, - _pwm_precision); -} + // determine the pwm value + if (rpm == 0) + pwm_value = _pwm_off_value; + else + pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value); -uint32_t _10vSpindle::set_rpm(uint32_t rpm) { - uint32_t pwm_value; - - if (_output_pin == UNDEFINED_PIN) + set_output(pwm_value); return rpm; + } + /* + void _10vSpindle::set_state(uint8_t state, uint32_t rpm) { + if (sys.abort) + return; // Block during abort. - // apply speed overrides - rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (percent) + if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm. + sys.spindle_speed = 0; + stop(); + } else { + set_spindle_dir_pin(state == SPINDLE_ENABLE_CW); + set_rpm(rpm); + } - // apply limits limits - if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm)) - rpm = _max_rpm; - else if (rpm != 0 && rpm <= _min_rpm) - rpm = _min_rpm; - sys.spindle_speed = rpm; + set_enable_pin(state != SPINDLE_DISABLE); - // determine the pwm value - if (rpm == 0) - pwm_value = _pwm_off_value; - else - pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value); + sys.report_ovr_counter = 0; // Set to report change immediately + } - set_output(pwm_value); - return rpm; -} -/* -void _10vSpindle::set_state(uint8_t state, uint32_t rpm) { - if (sys.abort) - return; // Block during abort. + */ - if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm. - sys.spindle_speed = 0; - stop(); - } else { - set_spindle_dir_pin(state == SPINDLE_ENABLE_CW); - set_rpm(rpm); + uint8_t _10vSpindle::get_state() { + if (_current_pwm_duty == 0 || _output_pin == UNDEFINED_PIN) + return (SPINDLE_STATE_DISABLE); + if (_direction_pin != UNDEFINED_PIN) + return digitalRead(_direction_pin) ? SPINDLE_STATE_CW : SPINDLE_STATE_CCW; + return (SPINDLE_STATE_CW); } - set_enable_pin(state != SPINDLE_DISABLE); + void _10vSpindle::stop() { + // inverts are delt with in methods + set_enable_pin(false); + set_output(_pwm_off_value); + } - sys.report_ovr_counter = 0; // Set to report change immediately -} - -*/ - -uint8_t _10vSpindle::get_state() { - if (_current_pwm_duty == 0 || _output_pin == UNDEFINED_PIN) - return (SPINDLE_STATE_DISABLE); - if (_direction_pin != UNDEFINED_PIN) - return digitalRead(_direction_pin) ? SPINDLE_STATE_CW : SPINDLE_STATE_CCW; - return (SPINDLE_STATE_CW); -} - -void _10vSpindle::stop() { - // inverts are delt with in methods - set_enable_pin(false); - set_output(_pwm_off_value); -} - -void _10vSpindle::set_enable_pin(bool enable) { - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "_10vSpindle::set_enable_pin"); - if (_off_with_zero_speed && sys.spindle_speed == 0) - enable = false; + void _10vSpindle::set_enable_pin(bool enable) { + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "_10vSpindle::set_enable_pin"); + if (_off_with_zero_speed && sys.spindle_speed == 0) + enable = false; #ifdef INVERT_SPINDLE_ENABLE_PIN - enable = !enable; + enable = !enable; #endif - digitalWrite(_enable_pin, enable); + digitalWrite(_enable_pin, enable); - // turn off anything that acts like an enable - if (!enable) { - digitalWrite(_direction_pin, enable); - digitalWrite(_forward_pin, enable); - digitalWrite(_reverse_pin, enable); + // turn off anything that acts like an enable + if (!enable) { + digitalWrite(_direction_pin, enable); + digitalWrite(_forward_pin, enable); + digitalWrite(_reverse_pin, enable); + } + } + + void _10vSpindle::set_spindle_dir_pin(bool Clockwise) { + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "_10vSpindle::set_spindle_dir_pin"); + digitalWrite(_direction_pin, Clockwise); + digitalWrite(_forward_pin, Clockwise); + digitalWrite(_reverse_pin, !Clockwise); } } - -void _10vSpindle::set_spindle_dir_pin(bool Clockwise) { - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "_10vSpindle::set_spindle_dir_pin"); - digitalWrite(_direction_pin, Clockwise); - digitalWrite(_forward_pin, Clockwise); - digitalWrite(_reverse_pin, !Clockwise); -} diff --git a/Grbl_Esp32/src/Spindles/10vSpindle.h b/Grbl_Esp32/src/Spindles/10vSpindle.h new file mode 100644 index 00000000..6aee0bd6 --- /dev/null +++ b/Grbl_Esp32/src/Spindles/10vSpindle.h @@ -0,0 +1,58 @@ +#pragma once + +/* + 10vSpindle.h + + This is basically a PWM spindle with some changes, so a separate forward and + reverse signal can be sent. + + The direction pins will act as enables for the 2 directions. There is usually + a min RPM with VFDs, that speed will remain even if speed is 0. You + must turn off both direction pins when enable is off. + + + Part of Grbl_ESP32 + 2020 - Bart Dring + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . +*/ + +#include "PWMSpindle.h" + +namespace Spindles { + class _10vSpindle : public PWMSpindle { + public: + _10vSpindle() = default; + + _10vSpindle(const _10vSpindle&) = delete; + _10vSpindle(_10vSpindle&&) = delete; + _10vSpindle& operator=(const _10vSpindle&) = delete; + _10vSpindle& operator=(_10vSpindle&&) = delete; + + void init() override; + void config_message() override; + uint32_t set_rpm(uint32_t rpm) override; + //void set_state(uint8_t state, uint32_t rpm); + + uint8_t get_state() override; + void stop() override; + + virtual ~_10vSpindle() {} + + uint8_t _forward_pin; + uint8_t _reverse_pin; + + protected: + void set_enable_pin(bool enable_pin) override; + void set_spindle_dir_pin(bool Clockwise) override; + }; +} diff --git a/Grbl_Esp32/src/Spindles/BESCSpindle.cpp b/Grbl_Esp32/src/Spindles/BESCSpindle.cpp index 07033203..f0d67ae0 100644 --- a/Grbl_Esp32/src/Spindles/BESCSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/BESCSpindle.cpp @@ -30,7 +30,7 @@ BESC_MAX_PULSE_SECS is typically 2ms (0.002 sec) or more */ -#include "SpindleClass.h" +#include "BESCSpindle.h" // don't change these #define BESC_PWM_FREQ 50.0f // Hz @@ -51,70 +51,72 @@ #define BESC_MIN_PULSE_CNT (uint16_t)(BESC_MIN_PULSE_SECS / BESC_PULSE_PERIOD * 65535.0) #define BESC_MAX_PULSE_CNT (uint16_t)(BESC_MAX_PULSE_SECS / BESC_PULSE_PERIOD * 65535.0) -void BESCSpindle ::init() { - get_pins_and_settings(); // these gets the standard PWM settings, but many need to be changed for BESC +namespace Spindles { + void BESCSpindle::init() { + get_pins_and_settings(); // these gets the standard PWM settings, but many need to be changed for BESC - if (_output_pin == UNDEFINED_PIN) { - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: BESC output pin not defined"); - return; // We cannot continue without the output pin + if (_output_pin == UNDEFINED_PIN) { + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: BESC output pin not defined"); + return; // We cannot continue without the output pin + } + + // override some settings to what is required for a BESC + _pwm_freq = (uint32_t)BESC_PWM_FREQ; + _pwm_precision = 16; + + // override these settings + _pwm_off_value = BESC_MIN_PULSE_CNT; + _pwm_min_value = _pwm_off_value; + _pwm_max_value = BESC_MAX_PULSE_CNT; + + ledcSetup(_spindle_pwm_chan_num, (double)_pwm_freq, _pwm_precision); // setup the channel + ledcAttachPin(_output_pin, _spindle_pwm_chan_num); // attach the PWM to the pin + + pinMode(_enable_pin, OUTPUT); + + set_rpm(0); + + use_delays = true; + + config_message(); } - // override some settings to what is required for a BESC - _pwm_freq = (uint32_t)BESC_PWM_FREQ; - _pwm_precision = 16; + // prints the startup message of the spindle config + void BESCSpindle::config_message() { + grbl_msg_sendf(CLIENT_SERIAL, + MSG_LEVEL_INFO, + "BESC spindle on Pin:%s Min:%0.2fms Max:%0.2fms Freq:%dHz Res:%dbits", + pinName(_output_pin).c_str(), + BESC_MIN_PULSE_SECS * 1000.0, // convert to milliseconds + BESC_MAX_PULSE_SECS * 1000.0, // convert to milliseconds + _pwm_freq, + _pwm_precision); + } - // override these settings - _pwm_off_value = BESC_MIN_PULSE_CNT; - _pwm_min_value = _pwm_off_value; - _pwm_max_value = BESC_MAX_PULSE_CNT; + uint32_t BESCSpindle::set_rpm(uint32_t rpm) { + uint32_t pwm_value; - ledcSetup(_spindle_pwm_chan_num, (double)_pwm_freq, _pwm_precision); // setup the channel - ledcAttachPin(_output_pin, _spindle_pwm_chan_num); // attach the PWM to the pin + if (_output_pin == UNDEFINED_PIN) + return rpm; - pinMode(_enable_pin, OUTPUT); + // apply speed overrides + rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (percent) - set_rpm(0); + // apply limits limits + if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm)) + rpm = _max_rpm; + else if (rpm != 0 && rpm <= _min_rpm) + rpm = _min_rpm; + sys.spindle_speed = rpm; - use_delays = true; + // determine the pwm value + if (rpm == 0) { + pwm_value = _pwm_off_value; + } else { + pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value); + } - config_message(); -} - -// prints the startup message of the spindle config -void BESCSpindle ::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, - MSG_LEVEL_INFO, - "BESC spindle on Pin:%s Min:%0.2fms Max:%0.2fms Freq:%dHz Res:%dbits", - pinName(_output_pin).c_str(), - BESC_MIN_PULSE_SECS * 1000.0, // convert to milliseconds - BESC_MAX_PULSE_SECS * 1000.0, // convert to milliseconds - _pwm_freq, - _pwm_precision); -} - -uint32_t BESCSpindle::set_rpm(uint32_t rpm) { - uint32_t pwm_value; - - if (_output_pin == UNDEFINED_PIN) + set_output(pwm_value); return rpm; - - // apply speed overrides - rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (percent) - - // apply limits limits - if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm)) - rpm = _max_rpm; - else if (rpm != 0 && rpm <= _min_rpm) - rpm = _min_rpm; - sys.spindle_speed = rpm; - - // determine the pwm value - if (rpm == 0) { - pwm_value = _pwm_off_value; - } else { - pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value); } - - set_output(pwm_value); - return rpm; } diff --git a/Grbl_Esp32/src/Spindles/BESCSpindle.h b/Grbl_Esp32/src/Spindles/BESCSpindle.h new file mode 100644 index 00000000..3d8b11a9 --- /dev/null +++ b/Grbl_Esp32/src/Spindles/BESCSpindle.h @@ -0,0 +1,54 @@ +#pragma once + +/* + BESCSpindle.cpp + + This a special type of PWM spindle for RC type Brushless DC Speed + controllers. They use a short pulse for off and a longer pulse for + full on. The pulse is always a small portion of the full cycle. + Some BESCs have a special turn on procedure. This may be a one time + procedure or must be done every time. The user must do that via gcode. + + Part of Grbl_ESP32 + 2020 - Bart Dring + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . + + Important ESC Settings + 50 Hz this is a typical frequency for an ESC + Some ESCs can handle higher frequencies, but there is no advantage to changing it. + + Determine the typical min and max pulse length of your ESC + BESC_MIN_PULSE_SECS is typically 1ms (0.001 sec) or less + BESC_MAX_PULSE_SECS is typically 2ms (0.002 sec) or more + +*/ + +#include "PWMSpindle.h" + +namespace Spindles { + class BESCSpindle : public PWMSpindle { + public: + BESCSpindle() = default; + + BESCSpindle(const BESCSpindle&) = delete; + BESCSpindle(BESCSpindle&&) = delete; + BESCSpindle& operator=(const BESCSpindle&) = delete; + BESCSpindle& operator=(BESCSpindle&&) = delete; + + void init() override; + void config_message() override; + uint32_t set_rpm(uint32_t rpm) override; + + virtual ~BESCSpindle() {} + }; +} diff --git a/Grbl_Esp32/src/Spindles/DacSpindle.cpp b/Grbl_Esp32/src/Spindles/DacSpindle.cpp index c05590e4..f3a51fad 100644 --- a/Grbl_Esp32/src/Spindles/DacSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/DacSpindle.cpp @@ -21,84 +21,86 @@ along with Grbl. If not, see . */ -#include "SpindleClass.h" +#include "DacSpindle.h" -// ======================================== DacSpindle ====================================== -void DacSpindle ::init() { - get_pins_and_settings(); +namespace Spindles { + // ======================================== DacSpindle ====================================== + void DacSpindle::init() { + get_pins_and_settings(); - if (_output_pin == UNDEFINED_PIN) - return; + if (_output_pin == UNDEFINED_PIN) + return; - _min_rpm = rpm_min->get(); - _max_rpm = rpm_max->get(); - _pwm_min_value = 0; // not actually PWM...DAC counts - _pwm_max_value = 255; // not actually PWM...DAC counts - _gpio_ok = true; + _min_rpm = rpm_min->get(); + _max_rpm = rpm_max->get(); + _pwm_min_value = 0; // not actually PWM...DAC counts + _pwm_max_value = 255; // not actually PWM...DAC counts + _gpio_ok = true; - if (_output_pin != GPIO_NUM_25 && _output_pin != GPIO_NUM_26) { // DAC can only be used on these pins - _gpio_ok = false; - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "DAC spindle pin invalid GPIO_NUM_%d (pin 25 or 26 only)", _output_pin); - return; - } - - pinMode(_enable_pin, OUTPUT); - pinMode(_direction_pin, OUTPUT); - - is_reversable = (_direction_pin != UNDEFINED_PIN); - use_delays = true; - - config_message(); -} - -void DacSpindle ::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, - MSG_LEVEL_INFO, - "DAC spindle Output:%s, Enbl:%s, Dir:%s, Res:8bits", - pinName(_output_pin).c_str(), - pinName(_enable_pin).c_str(), - pinName(_direction_pin).c_str()); -} - -uint32_t DacSpindle::set_rpm(uint32_t rpm) { - if (_output_pin == UNDEFINED_PIN) - return rpm; - - uint32_t pwm_value; - - // apply overrides and limits - rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (percent) - - // Calculate PWM register value based on rpm max/min settings and programmed rpm. - if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm)) { - // No PWM range possible. Set simple on/off spindle control pin state. - sys.spindle_speed = _max_rpm; - pwm_value = _pwm_max_value; - } else if (rpm <= _min_rpm) { - if (rpm == 0) { // S0 disables spindle - sys.spindle_speed = 0; - pwm_value = 0; - } else { // Set minimum PWM output - rpm = _min_rpm; - sys.spindle_speed = rpm; - pwm_value = 0; - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Spindle RPM less than min RPM:%5.2f %d", rpm, pwm_value); + if (_output_pin != GPIO_NUM_25 && _output_pin != GPIO_NUM_26) { // DAC can only be used on these pins + _gpio_ok = false; + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "DAC spindle pin invalid GPIO_NUM_%d (pin 25 or 26 only)", _output_pin); + return; } - } else { - // Compute intermediate PWM value with linear spindle speed model. - // NOTE: A nonlinear model could be installed here, if required, but keep it VERY light-weight. - sys.spindle_speed = rpm; - pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value); + pinMode(_enable_pin, OUTPUT); + pinMode(_direction_pin, OUTPUT); + + is_reversable = (_direction_pin != UNDEFINED_PIN); + use_delays = true; + + config_message(); } - set_output(pwm_value); + void DacSpindle::config_message() { + grbl_msg_sendf(CLIENT_SERIAL, + MSG_LEVEL_INFO, + "DAC spindle Output:%s, Enbl:%s, Dir:%s, Res:8bits", + pinName(_output_pin).c_str(), + pinName(_enable_pin).c_str(), + pinName(_direction_pin).c_str()); + } - return rpm; -} + uint32_t DacSpindle::set_rpm(uint32_t rpm) { + if (_output_pin == UNDEFINED_PIN) + return rpm; -void DacSpindle ::set_output(uint32_t duty) { - if (_gpio_ok) { - dacWrite(_output_pin, (uint8_t)duty); + uint32_t pwm_value; + + // apply overrides and limits + rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (percent) + + // Calculate PWM register value based on rpm max/min settings and programmed rpm. + if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm)) { + // No PWM range possible. Set simple on/off spindle control pin state. + sys.spindle_speed = _max_rpm; + pwm_value = _pwm_max_value; + } else if (rpm <= _min_rpm) { + if (rpm == 0) { // S0 disables spindle + sys.spindle_speed = 0; + pwm_value = 0; + } else { // Set minimum PWM output + rpm = _min_rpm; + sys.spindle_speed = rpm; + pwm_value = 0; + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Spindle RPM less than min RPM:%5.2f %d", rpm, pwm_value); + } + } else { + // Compute intermediate PWM value with linear spindle speed model. + // NOTE: A nonlinear model could be installed here, if required, but keep it VERY light-weight. + sys.spindle_speed = rpm; + + pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value); + } + + set_output(pwm_value); + + return rpm; + } + + void DacSpindle::set_output(uint32_t duty) { + if (_gpio_ok) { + dacWrite(_output_pin, (uint8_t)duty); + } } } diff --git a/Grbl_Esp32/src/Spindles/DacSpindle.h b/Grbl_Esp32/src/Spindles/DacSpindle.h new file mode 100644 index 00000000..b357769d --- /dev/null +++ b/Grbl_Esp32/src/Spindles/DacSpindle.h @@ -0,0 +1,51 @@ +#pragma once + +/* + DacSpindle.cpp + + This uses the Analog DAC in the ESP32 to generate a voltage + proportional to the GCode S value desired. Some spindle uses + a 0-5V or 0-10V value to control the spindle. You would use + an Op Amp type circuit to get from the 0.3.3V of the ESP32 to that voltage. + + Part of Grbl_ESP32 + 2020 - Bart Dring + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . + +*/ + +#include "PWMSpindle.h" + +namespace Spindles { + // This uses one of the (2) DAC pins on ESP32 to output a voltage + class DacSpindle : public PWMSpindle { + public: + DacSpindle() = default; + + DacSpindle(const DacSpindle&) = delete; + DacSpindle(DacSpindle&&) = delete; + DacSpindle& operator=(const DacSpindle&) = delete; + DacSpindle& operator=(DacSpindle&&) = delete; + + void init() override; + void config_message() override; + uint32_t set_rpm(uint32_t rpm) override; + + virtual ~DacSpindle() {} + + private: + bool _gpio_ok; // DAC is on a valid pin + protected: + void set_output(uint32_t duty); // sets DAC instead of PWM + }; +} diff --git a/Grbl_Esp32/src/Spindles/HuanyangSpindle.cpp b/Grbl_Esp32/src/Spindles/HuanyangSpindle.cpp index 1b1d1a64..51d0d167 100644 --- a/Grbl_Esp32/src/Spindles/HuanyangSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/HuanyangSpindle.cpp @@ -109,9 +109,9 @@ */ -#include "SpindleClass.h" +#include "HuanyangSpindle.h" -#include "driver/uart.h" +#include #define HUANYANG_UART_PORT UART_NUM_2 // hard coded for this port right now #define ECHO_TEST_CTS UART_PIN_NO_CHANGE // CTS pin is not used @@ -131,337 +131,335 @@ # define HUANYANG_BAUD_RATE 9600 // PD164 setting #endif -// communication task and queue stuff -typedef struct { - uint8_t tx_length; - uint8_t rx_length; - bool critical; - char msg[HUANYANG_MAX_MSG_SIZE]; -} hy_command_t; +namespace Spindles { + // communication task and queue stuff + typedef struct { + uint8_t tx_length; + uint8_t rx_length; + bool critical; + char msg[HUANYANG_MAX_MSG_SIZE]; + } hy_command_t; -typedef enum : uint8_t { - READ_SET_FREQ = 0, // The set frequency - READ_OUTPUT_FREQ = 1, // The current operating frequency - READ_OUTPUT_AMPS = 2, // - READ_SET_RPM = 3, // This is the last requested freq even in off mode - READ_DC_VOLTAGE = 4, // - READ_AC_VOLTAGE = 5, // - READ_CONT = 6, // counting value??? - READ_TEMP = 7, // -} read_register_t; + typedef enum : uint8_t { + READ_SET_FREQ = 0, // The set frequency + READ_OUTPUT_FREQ = 1, // The current operating frequency + READ_OUTPUT_AMPS = 2, // + READ_SET_RPM = 3, // This is the last requested freq even in off mode + READ_DC_VOLTAGE = 4, // + READ_AC_VOLTAGE = 5, // + READ_CONT = 6, // counting value??? + READ_TEMP = 7, // + } read_register_t; -QueueHandle_t hy_cmd_queue; + QueueHandle_t hy_cmd_queue; -static TaskHandle_t vfd_cmdTaskHandle = 0; + static TaskHandle_t vfd_cmdTaskHandle = 0; -bool hy_spindle_ok = true; + bool hy_spindle_ok = true; -// The communications task -void vfd_cmd_task(void* pvParameters) { - static bool unresponsive = false; // to pop off a message once each time it becomes unresponsive - uint8_t reg_item = 0x00; - hy_command_t next_cmd; - uint8_t rx_message[HUANYANG_MAX_MSG_SIZE]; + // The communications task + void vfd_cmd_task(void* pvParameters) { + static bool unresponsive = false; // to pop off a message once each time it becomes unresponsive + uint8_t reg_item = 0x00; + hy_command_t next_cmd; + uint8_t rx_message[HUANYANG_MAX_MSG_SIZE]; - while (true) { - if (xQueueReceive(hy_cmd_queue, &next_cmd, 0) == pdTRUE) { - uart_flush(HUANYANG_UART_PORT); - //report_hex_msg(next_cmd.msg, "Tx: ", next_cmd.tx_length); - uart_write_bytes(HUANYANG_UART_PORT, next_cmd.msg, next_cmd.tx_length); + while (true) { + if (xQueueReceive(hy_cmd_queue, &next_cmd, 0) == pdTRUE) { + uart_flush(HUANYANG_UART_PORT); + //report_hex_msg(next_cmd.msg, "Tx: ", next_cmd.tx_length); + uart_write_bytes(HUANYANG_UART_PORT, next_cmd.msg, next_cmd.tx_length); - uint16_t read_length = uart_read_bytes(HUANYANG_UART_PORT, rx_message, next_cmd.rx_length, RESPONSE_WAIT_TICKS); + uint16_t read_length = uart_read_bytes(HUANYANG_UART_PORT, rx_message, next_cmd.rx_length, RESPONSE_WAIT_TICKS); - if (read_length < next_cmd.rx_length) { - if (!unresponsive) { - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Spindle RS485 Unresponsive %d", read_length); - if (next_cmd.critical) { - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Critical Spindle RS485 Unresponsive"); - system_set_exec_alarm(EXEC_ALARM_SPINDLE_CONTROL); + if (read_length < next_cmd.rx_length) { + if (!unresponsive) { + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Spindle RS485 Unresponsive %d", read_length); + if (next_cmd.critical) { + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Critical Spindle RS485 Unresponsive"); + system_set_exec_alarm(EXEC_ALARM_SPINDLE_CONTROL); + } + unresponsive = true; } - unresponsive = true; + } else { + // success + unresponsive = false; + //report_hex_msg(rx_message, "Rx: ", read_length); + uint32_t ret_value = ((uint32_t)rx_message[4] << 8) + rx_message[5]; + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Item:%d value:%05d ", rx_message[3], ret_value); } + } else { - // success - unresponsive = false; - //report_hex_msg(rx_message, "Rx: ", read_length); - uint32_t ret_value = ((uint32_t)rx_message[4] << 8) + rx_message[5]; - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Item:%d value:%05d ", rx_message[3], ret_value); - } - - } else { - HuanyangSpindle ::read_value(reg_item); // only this appears to work all the time. Other registers are flakey. - if (reg_item < 0x03) - reg_item++; - else { - reg_item = 0x00; + HuanyangSpindle::read_value(reg_item); // only this appears to work all the time. Other registers are flakey. + if (reg_item < 0x03) + reg_item++; + else { + reg_item = 0x00; + } } + vTaskDelay(HUANYANG_POLL_RATE); // TODO: What is the best value here? } - vTaskDelay(HUANYANG_POLL_RATE); // TODO: What is the best value here? - } -} - -// ================== Class methods ================================== - -void HuanyangSpindle ::init() { - hy_spindle_ok = true; // initialize - - // fail if required items are not defined - if (!get_pins_and_settings()) { - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Huanyang spindle errors"); - return; } - if (!_task_running) { // init can happen many times, we only want to start one task - hy_cmd_queue = xQueueCreate(HUANYANG_QUEUE_SIZE, sizeof(hy_command_t)); - xTaskCreatePinnedToCore(vfd_cmd_task, // task - "vfd_cmdTaskHandle", // name for task - 2048, // size of task stack - NULL, // parameters - 1, // priority - &vfd_cmdTaskHandle, - 0 // core - ); - _task_running = true; + // ================== Class methods ================================== + + void HuanyangSpindle::init() { + hy_spindle_ok = true; // initialize + + // fail if required items are not defined + if (!get_pins_and_settings()) { + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Huanyang spindle errors"); + return; + } + + if (!_task_running) { // init can happen many times, we only want to start one task + hy_cmd_queue = xQueueCreate(HUANYANG_QUEUE_SIZE, sizeof(hy_command_t)); + xTaskCreatePinnedToCore(vfd_cmd_task, // task + "vfd_cmdTaskHandle", // name for task + 2048, // size of task stack + NULL, // parameters + 1, // priority + &vfd_cmdTaskHandle, + 0 // core + ); + _task_running = true; + } + + // this allows us to init() again later. + // If you change certain settings, init() gets called agian + uart_driver_delete(HUANYANG_UART_PORT); + + uart_config_t uart_config = { + .baud_rate = HUANYANG_BAUD_RATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .rx_flow_ctrl_thresh = 122, + }; + + uart_param_config(HUANYANG_UART_PORT, &uart_config); + + uart_set_pin(HUANYANG_UART_PORT, _txd_pin, _rxd_pin, _rts_pin, UART_PIN_NO_CHANGE); + + uart_driver_install(HUANYANG_UART_PORT, HUANYANG_BUF_SIZE * 2, 0, 0, NULL, 0); + + uart_set_mode(HUANYANG_UART_PORT, UART_MODE_RS485_HALF_DUPLEX); + + is_reversable = true; // these VFDs are always reversable + use_delays = true; + + // + _current_rpm = 0; + _state = SPINDLE_DISABLE; + + config_message(); } - // this allows us to init() again later. - // If you change certain settings, init() gets called agian - uart_driver_delete(HUANYANG_UART_PORT); - - uart_config_t uart_config = { - .baud_rate = HUANYANG_BAUD_RATE, - .data_bits = UART_DATA_8_BITS, - .parity = UART_PARITY_DISABLE, - .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, - .rx_flow_ctrl_thresh = 122, - }; - - uart_param_config(HUANYANG_UART_PORT, &uart_config); - - uart_set_pin(HUANYANG_UART_PORT, _txd_pin, _rxd_pin, _rts_pin, UART_PIN_NO_CHANGE); - - uart_driver_install(HUANYANG_UART_PORT, HUANYANG_BUF_SIZE * 2, 0, 0, NULL, 0); - - uart_set_mode(HUANYANG_UART_PORT, UART_MODE_RS485_HALF_DUPLEX); - - is_reversable = true; // these VFDs are always reversable - use_delays = true; - - // - _current_rpm = 0; - _state = SPINDLE_DISABLE; - - config_message(); -} - -// Checks for all the required pin definitions -// It returns a message for each missing pin -// Returns true if all pins are defined. -bool HuanyangSpindle ::get_pins_and_settings() { + // Checks for all the required pin definitions + // It returns a message for each missing pin + // Returns true if all pins are defined. + bool HuanyangSpindle::get_pins_and_settings() { #ifdef HUANYANG_TXD_PIN - _txd_pin = HUANYANG_TXD_PIN; + _txd_pin = HUANYANG_TXD_PIN; #else - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_TXD_PIN"); - hy_spindle_ok = false; + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_TXD_PIN"); + hy_spindle_ok = false; #endif #ifdef HUANYANG_RXD_PIN - _rxd_pin = HUANYANG_RXD_PIN; + _rxd_pin = HUANYANG_RXD_PIN; #else - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_RXD_PIN"); - hy_spindle_ok = false; + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_RXD_PIN"); + hy_spindle_ok = false; #endif #ifdef HUANYANG_RTS_PIN - _rts_pin = HUANYANG_RTS_PIN; + _rts_pin = HUANYANG_RTS_PIN; #else - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_RTS_PIN"); - hy_spindle_ok = false; + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_RTS_PIN"); + hy_spindle_ok = false; #endif - if (laser_mode->get()) { - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Huanyang spindle disabled in laser mode. Set $GCode/LaserMode=Off and restart"); - hy_spindle_ok = false; + if (laser_mode->get()) { + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Huanyang spindle disabled in laser mode. Set $GCode/LaserMode=Off and restart"); + hy_spindle_ok = false; + } + + _min_rpm = rpm_min->get(); + _max_rpm = rpm_max->get(); + + return hy_spindle_ok; } - _min_rpm = rpm_min->get(); - _max_rpm = rpm_max->get(); + void HuanyangSpindle::config_message() { + grbl_msg_sendf(CLIENT_SERIAL, + MSG_LEVEL_INFO, + "Huanyang Spindle Tx:%s Rx:%s RTS:%s", + pinName(_txd_pin).c_str(), + pinName(_rxd_pin).c_str(), + pinName(_rts_pin).c_str()); + } - return hy_spindle_ok; -} + void HuanyangSpindle::set_state(uint8_t state, uint32_t rpm) { + if (sys.abort) + return; // Block during abort. -void HuanyangSpindle ::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, - MSG_LEVEL_INFO, - "Huanyang Spindle Tx:%s Rx:%s RTS:%s", - pinName(_txd_pin).c_str(), - pinName(_rxd_pin).c_str(), - pinName(_rts_pin).c_str()); -} + bool critical = (sys.state == STATE_CYCLE || state != SPINDLE_DISABLE); -void HuanyangSpindle ::set_state(uint8_t state, uint32_t rpm) { - if (sys.abort) - return; // Block during abort. - - bool critical = (sys.state == STATE_CYCLE || state != SPINDLE_DISABLE); - - if (_current_state != state) { // already at the desired state. This function gets called a lot. - set_mode(state, critical); // critical if we are in a job - set_rpm(rpm); - if (state == SPINDLE_DISABLE) { - sys.spindle_speed = 0; - if (_current_state != state) - mc_dwell(spindle_delay_spindown->get()); - } else { - if (_current_state != state) - mc_dwell(spindle_delay_spinup->get()); - } - } else { - if (_current_rpm != rpm) + if (_current_state != state) { // already at the desired state. This function gets called a lot. + set_mode(state, critical); // critical if we are in a job set_rpm(rpm); - } - - _current_state = state; // store locally for faster get_state() - - sys.report_ovr_counter = 0; // Set to report change immediately - - return; -} - -bool HuanyangSpindle ::set_mode(uint8_t mode, bool critical) { - if (!hy_spindle_ok) - return false; - - hy_command_t mode_cmd; - - mode_cmd.tx_length = 6; - mode_cmd.rx_length = 6; - - mode_cmd.msg[0] = HUANYANG_ADDR; - mode_cmd.msg[1] = 0x03; - mode_cmd.msg[2] = 0x01; - - if (mode == SPINDLE_ENABLE_CW) - mode_cmd.msg[3] = 0x01; - else if (mode == SPINDLE_ENABLE_CCW) - mode_cmd.msg[3] = 0x11; - else { //SPINDLE_DISABLE - mode_cmd.msg[3] = 0x08; - - if (!xQueueReset(hy_cmd_queue)) { - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD spindle off, queue could not be reset"); + if (state == SPINDLE_DISABLE) { + sys.spindle_speed = 0; + if (_current_state != state) + mc_dwell(spindle_delay_spindown->get()); + } else { + if (_current_state != state) + mc_dwell(spindle_delay_spinup->get()); + } + } else { + if (_current_rpm != rpm) + set_rpm(rpm); } + + _current_state = state; // store locally for faster get_state() + + sys.report_ovr_counter = 0; // Set to report change immediately + + return; } - add_ModRTU_CRC(mode_cmd.msg, mode_cmd.rx_length); + bool HuanyangSpindle::set_mode(uint8_t mode, bool critical) { + if (!hy_spindle_ok) + return false; - mode_cmd.critical = critical; + hy_command_t mode_cmd; - if (xQueueSend(hy_cmd_queue, &mode_cmd, 0) != pdTRUE) - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD Queue Full"); + mode_cmd.tx_length = 6; + mode_cmd.rx_length = 6; - return true; -} + mode_cmd.msg[0] = HUANYANG_ADDR; + mode_cmd.msg[1] = 0x03; + mode_cmd.msg[2] = 0x01; -uint32_t HuanyangSpindle ::set_rpm(uint32_t rpm) { - if (!hy_spindle_ok) - return 0; + if (mode == SPINDLE_ENABLE_CW) + mode_cmd.msg[3] = 0x01; + else if (mode == SPINDLE_ENABLE_CCW) + mode_cmd.msg[3] = 0x11; + else { //SPINDLE_DISABLE + mode_cmd.msg[3] = 0x08; - hy_command_t rpm_cmd; + if (!xQueueReset(hy_cmd_queue)) { + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD spindle off, queue could not be reset"); + } + } - // apply override - rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (uint8_t percent) + add_ModRTU_CRC(mode_cmd.msg, mode_cmd.rx_length); - // apply limits - if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm)) - rpm = _max_rpm; - else if (rpm != 0 && rpm <= _min_rpm) - rpm = _min_rpm; + mode_cmd.critical = critical; - sys.spindle_speed = rpm; + if (xQueueSend(hy_cmd_queue, &mode_cmd, 0) != pdTRUE) + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD Queue Full"); + + return true; + } + + uint32_t HuanyangSpindle::set_rpm(uint32_t rpm) { + if (!hy_spindle_ok) + return 0; + + hy_command_t rpm_cmd; + + // apply override + rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (uint8_t percent) + + // apply limits + if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm)) + rpm = _max_rpm; + else if (rpm != 0 && rpm <= _min_rpm) + rpm = _min_rpm; + + sys.spindle_speed = rpm; + + if (rpm == _current_rpm) // prevent setting same RPM twice + return rpm; + + _current_rpm = rpm; + + // TODO add the speed modifiers override, linearization, etc. + + rpm_cmd.tx_length = 7; + rpm_cmd.rx_length = 6; + + rpm_cmd.msg[0] = HUANYANG_ADDR; + rpm_cmd.msg[1] = 0x05; + rpm_cmd.msg[2] = 0x02; + + uint16_t data = (uint16_t)(rpm * 100 / 60); // send Hz * 10 (Ex:1500 RPM = 25Hz .... Send 2500) + + rpm_cmd.msg[3] = (data & 0xFF00) >> 8; + rpm_cmd.msg[4] = (data & 0xFF); + + add_ModRTU_CRC(rpm_cmd.msg, rpm_cmd.tx_length); + + rpm_cmd.critical = false; + + if (xQueueSend(hy_cmd_queue, &rpm_cmd, 0) != pdTRUE) + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD Queue Full"); - if (rpm == _current_rpm) // prevent setting same RPM twice return rpm; - - _current_rpm = rpm; - - // TODO add the speed modifiers override, linearization, etc. - - rpm_cmd.tx_length = 7; - rpm_cmd.rx_length = 6; - - rpm_cmd.msg[0] = HUANYANG_ADDR; - rpm_cmd.msg[1] = 0x05; - rpm_cmd.msg[2] = 0x02; - - uint16_t data = (uint16_t)(rpm * 100 / 60); // send Hz * 10 (Ex:1500 RPM = 25Hz .... Send 2500) - - rpm_cmd.msg[3] = (data & 0xFF00) >> 8; - rpm_cmd.msg[4] = (data & 0xFF); - - add_ModRTU_CRC(rpm_cmd.msg, rpm_cmd.tx_length); - - rpm_cmd.critical = false; - - if (xQueueSend(hy_cmd_queue, &rpm_cmd, 0) != pdTRUE) - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD Queue Full"); - - return rpm; -} - -// This appears to read the control register and will return an RPM running or not. -void HuanyangSpindle ::read_value(uint8_t reg) { - uint16_t ret_value = 0; - hy_command_t read_cmd; - uint8_t rx_message[HUANYANG_MAX_MSG_SIZE]; - - read_cmd.tx_length = 8; - read_cmd.rx_length = 8; - - read_cmd.msg[0] = HUANYANG_ADDR; - read_cmd.msg[1] = 0x04; - read_cmd.msg[2] = 0x03; - - read_cmd.msg[3] = reg; - - read_cmd.msg[4] = 0x00; - read_cmd.msg[5] = 0x00; - - read_cmd.critical = (sys.state == STATE_CYCLE); // only critical if running a job TBD.... maybe spindle on? - - add_ModRTU_CRC(read_cmd.msg, read_cmd.tx_length); - - if (xQueueSend(hy_cmd_queue, &read_cmd, 0) != pdTRUE) - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD Queue Full"); -} - -void HuanyangSpindle ::stop() { - set_mode(SPINDLE_DISABLE, false); -} - -// state is cached rather than read right now to prevent delays -uint8_t HuanyangSpindle ::get_state() { - return _state; -} - -// Calculate the CRC on all of the byte except the last 2 -// It then added the CRC to those last 2 bytes -// full_msg_len This is the length of the message including the 2 crc bytes -// Source: https://ctlsys.com/support/how_to_compute_the_modbus_rtu_message_crc/ -void HuanyangSpindle ::add_ModRTU_CRC(char* buf, int full_msg_len) { - uint16_t crc = 0xFFFF; - for (int pos = 0; pos < full_msg_len - 2; pos++) { - crc ^= (uint16_t)buf[pos]; // XOR byte into least sig. byte of crc - for (int i = 8; i != 0; i--) { // Loop over each bit - if ((crc & 0x0001) != 0) { // If the LSB is set - crc >>= 1; // Shift right and XOR 0xA001 - crc ^= 0xA001; - } else // Else LSB is not set - crc >>= 1; // Just shift right - } } - // add the calculated Crc to the message - buf[full_msg_len - 1] = (crc & 0xFF00) >> 8; - buf[full_msg_len - 2] = (crc & 0xFF); + + // This appears to read the control register and will return an RPM running or not. + void HuanyangSpindle::read_value(uint8_t reg) { + uint16_t ret_value = 0; + hy_command_t read_cmd; + uint8_t rx_message[HUANYANG_MAX_MSG_SIZE]; + + read_cmd.tx_length = 8; + read_cmd.rx_length = 8; + + read_cmd.msg[0] = HUANYANG_ADDR; + read_cmd.msg[1] = 0x04; + read_cmd.msg[2] = 0x03; + + read_cmd.msg[3] = reg; + + read_cmd.msg[4] = 0x00; + read_cmd.msg[5] = 0x00; + + read_cmd.critical = (sys.state == STATE_CYCLE); // only critical if running a job TBD.... maybe spindle on? + + add_ModRTU_CRC(read_cmd.msg, read_cmd.tx_length); + + if (xQueueSend(hy_cmd_queue, &read_cmd, 0) != pdTRUE) + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD Queue Full"); + } + + void HuanyangSpindle::stop() { set_mode(SPINDLE_DISABLE, false); } + + // state is cached rather than read right now to prevent delays + uint8_t HuanyangSpindle::get_state() { return _state; } + + // Calculate the CRC on all of the byte except the last 2 + // It then added the CRC to those last 2 bytes + // full_msg_len This is the length of the message including the 2 crc bytes + // Source: https://ctlsys.com/support/how_to_compute_the_modbus_rtu_message_crc/ + void HuanyangSpindle::add_ModRTU_CRC(char* buf, int full_msg_len) { + uint16_t crc = 0xFFFF; + for (int pos = 0; pos < full_msg_len - 2; pos++) { + crc ^= (uint16_t)buf[pos]; // XOR byte into least sig. byte of crc + for (int i = 8; i != 0; i--) { // Loop over each bit + if ((crc & 0x0001) != 0) { // If the LSB is set + crc >>= 1; // Shift right and XOR 0xA001 + crc ^= 0xA001; + } else // Else LSB is not set + crc >>= 1; // Just shift right + } + } + // add the calculated Crc to the message + buf[full_msg_len - 1] = (crc & 0xFF00) >> 8; + buf[full_msg_len - 2] = (crc & 0xFF); + } } diff --git a/Grbl_Esp32/src/Spindles/HuanyangSpindle.h b/Grbl_Esp32/src/Spindles/HuanyangSpindle.h new file mode 100644 index 00000000..d16ada5d --- /dev/null +++ b/Grbl_Esp32/src/Spindles/HuanyangSpindle.h @@ -0,0 +1,62 @@ +#pragma once + +/* + HuanyangSpindle.h + + Part of Grbl_ESP32 + 2020 - Bart Dring + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . + +*/ +#include "Spindle.h" + +namespace Spindles { + class HuanyangSpindle : public Spindle { + private: + uint16_t ModRTU_CRC(char* buf, int len); + + bool set_mode(uint8_t mode, bool critical); + + bool get_pins_and_settings(); + + uint32_t _current_rpm; + uint8_t _txd_pin; + uint8_t _rxd_pin; + uint8_t _rts_pin; + uint8_t _state; + bool _task_running; + + public: + HuanyangSpindle() : _task_running(false) {} + + HuanyangSpindle(const HuanyangSpindle&) = delete; + HuanyangSpindle(HuanyangSpindle&&) = delete; + HuanyangSpindle& operator=(const HuanyangSpindle&) = delete; + HuanyangSpindle& operator=(HuanyangSpindle&&) = delete; + + void init(); + void config_message(); + void set_state(uint8_t state, uint32_t rpm); + uint8_t get_state(); + uint32_t set_rpm(uint32_t rpm); + void stop(); + static void read_value(uint8_t reg); + static void add_ModRTU_CRC(char* buf, int full_msg_len); + + virtual ~HuanyangSpindle() {} + + protected: + uint32_t _min_rpm; + uint32_t _max_rpm; + }; +} diff --git a/Grbl_Esp32/src/Spindles/Laser.cpp b/Grbl_Esp32/src/Spindles/Laser.cpp index d42bb7db..40b9e45a 100644 --- a/Grbl_Esp32/src/Spindles/Laser.cpp +++ b/Grbl_Esp32/src/Spindles/Laser.cpp @@ -19,22 +19,24 @@ along with Grbl. If not, see . */ -#include "SpindleClass.h" +#include "Laser.h" // ===================================== Laser ============================================== -bool Laser ::isRateAdjusted() { - return true; // can use M4 (CCW) laser mode. -} +namespace Spindles { + bool Laser::isRateAdjusted() { + return true; // can use M4 (CCW) laser mode. + } -void Laser ::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, - MSG_LEVEL_INFO, - "Laser spindle on Pin:%s, Freq:%.2fHz, Res:%dbits Laser mode:$32=%d", - pinName(_output_pin).c_str(), - _pwm_freq, - _pwm_precision, - isRateAdjusted()); // the current mode + void Laser::config_message() { + grbl_msg_sendf(CLIENT_SERIAL, + MSG_LEVEL_INFO, + "Laser spindle on Pin:%s, Freq:%.2fHz, Res:%dbits Laser mode:$32=%d", + pinName(_output_pin).c_str(), + _pwm_freq, + _pwm_precision, + isRateAdjusted()); // the current mode - use_delays = false; // this will override the value set in PWMSpindle intit() + use_delays = false; // this will override the value set in PWMSpindle intit() + } } diff --git a/Grbl_Esp32/src/Spindles/Laser.h b/Grbl_Esp32/src/Spindles/Laser.h new file mode 100644 index 00000000..9c7e1d9a --- /dev/null +++ b/Grbl_Esp32/src/Spindles/Laser.h @@ -0,0 +1,42 @@ +#pragma once + +/* + Laser.h + + This is similar the the PWM Spindle except that it allows the + M4 speed vs. power copensation. + + Part of Grbl_ESP32 + 2020 - Bart Dring + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . + +*/ +#include "PWMSpindle.h" + +namespace Spindles { + // this is the same as a PWM spindle but the M4 compensation is supported. + class Laser : public PWMSpindle { + public: + Laser() = default; + + Laser(const Laser&) = delete; + Laser(Laser&&) = delete; + Laser& operator=(const Laser&) = delete; + Laser& operator=(Laser&&) = delete; + + bool isRateAdjusted() override; + void config_message() override; + + virtual ~Laser() {} + }; +} diff --git a/Grbl_Esp32/src/Spindles/NullSpindle.cpp b/Grbl_Esp32/src/Spindles/NullSpindle.cpp index 51fe94b9..f236d814 100644 --- a/Grbl_Esp32/src/Spindles/NullSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/NullSpindle.cpp @@ -19,24 +19,20 @@ along with Grbl. If not, see . */ -#include "SpindleClass.h" +#include "NullSpindle.h" -// ======================= NullSpindle ============================== -// NullSpindle is just bunch of do nothing (ignore) methods to be used when you don't want a spindle +namespace Spindles { + // ======================= NullSpindle ============================== + // NullSpindle is just bunch of do nothing (ignore) methods to be used when you don't want a spindle -void NullSpindle ::init() { - is_reversable = false; - use_delays = false; - config_message(); -} -uint32_t NullSpindle ::set_rpm(uint32_t rpm) { - return rpm; -} -void NullSpindle ::set_state(uint8_t state, uint32_t rpm) {} -uint8_t NullSpindle ::get_state() { - return (SPINDLE_STATE_DISABLE); -} -void NullSpindle ::stop() {} -void NullSpindle ::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "No spindle"); + void NullSpindle::init() { + is_reversable = false; + use_delays = false; + config_message(); + } + uint32_t NullSpindle::set_rpm(uint32_t rpm) { return rpm; } + void NullSpindle::set_state(uint8_t state, uint32_t rpm) {} + uint8_t NullSpindle::get_state() { return (SPINDLE_STATE_DISABLE); } + void NullSpindle::stop() {} + void NullSpindle::config_message() { grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "No spindle"); } } diff --git a/Grbl_Esp32/src/Spindles/NullSpindle.h b/Grbl_Esp32/src/Spindles/NullSpindle.h new file mode 100644 index 00000000..4d115e85 --- /dev/null +++ b/Grbl_Esp32/src/Spindles/NullSpindle.h @@ -0,0 +1,47 @@ +#pragma once + +/* + NullSpindle.h + + This is used when you don't want to use a spindle No I/O will be used + and most methods don't do anything + + Part of Grbl_ESP32 + 2020 - Bart Dring + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . + +*/ +#include "Spindle.h" + +namespace Spindles { + // This is a dummy spindle that has no I/O. + // It is used to ignore spindle commands when no spinde is desired + class NullSpindle : public Spindle { + public: + NullSpindle() = default; + + NullSpindle(const NullSpindle&) = delete; + NullSpindle(NullSpindle&&) = delete; + NullSpindle& operator=(const NullSpindle&) = delete; + NullSpindle& operator=(NullSpindle&&) = delete; + + void init() override; + uint32_t set_rpm(uint32_t rpm) override; + void set_state(uint8_t state, uint32_t rpm) override; + uint8_t get_state() override; + void stop() override; + void config_message() override; + + virtual ~NullSpindle() {} + }; +} diff --git a/Grbl_Esp32/src/Spindles/PWMSpindle.cpp b/Grbl_Esp32/src/Spindles/PWMSpindle.cpp index 21dcb742..aadb3c5f 100644 --- a/Grbl_Esp32/src/Spindles/PWMSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/PWMSpindle.cpp @@ -19,7 +19,7 @@ along with Grbl. If not, see . */ -#include "SpindleClass.h" +#include "PWMSpindle.h" // ======================= PWMSpindle ============================== /* @@ -29,230 +29,230 @@ //#include "grbl.h" -void PWMSpindle ::init() { - get_pins_and_settings(); +namespace Spindles { + void PWMSpindle::init() { + get_pins_and_settings(); - if (_output_pin == UNDEFINED_PIN) { - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Spindle output pin not defined"); - return; // We cannot continue without the output pin + if (_output_pin == UNDEFINED_PIN) { + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Spindle output pin not defined"); + return; // We cannot continue without the output pin + } + + if (_output_pin >= I2S_OUT_PIN_BASE) { + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Spindle output pin %s cannot do PWM", pinName(_output_pin).c_str()); + return; + } + + ledcSetup(_spindle_pwm_chan_num, (double)_pwm_freq, _pwm_precision); // setup the channel + ledcAttachPin(_output_pin, _spindle_pwm_chan_num); // attach the PWM to the pin + + pinMode(_enable_pin, OUTPUT); + pinMode(_direction_pin, OUTPUT); + + use_delays = true; + + config_message(); } - if (_output_pin >= I2S_OUT_PIN_BASE) { - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Spindle output pin %s cannot do PWM", pinName(_output_pin).c_str()); - return; - } - - ledcSetup(_spindle_pwm_chan_num, (double)_pwm_freq, _pwm_precision); // setup the channel - ledcAttachPin(_output_pin, _spindle_pwm_chan_num); // attach the PWM to the pin - - pinMode(_enable_pin, OUTPUT); - pinMode(_direction_pin, OUTPUT); - - use_delays = true; - - config_message(); -} - -// Get the GPIO from the machine definition -void PWMSpindle ::get_pins_and_settings() { - // setup all the pins + // Get the GPIO from the machine definition + void PWMSpindle::get_pins_and_settings() { + // setup all the pins #ifdef SPINDLE_OUTPUT_PIN - _output_pin = SPINDLE_OUTPUT_PIN; + _output_pin = SPINDLE_OUTPUT_PIN; #else - _output_pin = UNDEFINED_PIN; + _output_pin = UNDEFINED_PIN; #endif #ifdef INVERT_SPINDLE_OUTPUT_PIN - _invert_pwm = true; + _invert_pwm = true; #else - _invert_pwm = false; + _invert_pwm = false; #endif #ifdef SPINDLE_ENABLE_PIN - _enable_pin = SPINDLE_ENABLE_PIN; + _enable_pin = SPINDLE_ENABLE_PIN; # ifdef SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED - _off_with_zero_speed = true; + _off_with_zero_speed = true; # endif #else - _enable_pin = UNDEFINED_PIN; - _off_with_zero_speed = false; + _enable_pin = UNDEFINED_PIN; + _off_with_zero_speed = false; #endif #ifdef SPINDLE_DIR_PIN - _direction_pin = SPINDLE_DIR_PIN; + _direction_pin = SPINDLE_DIR_PIN; #else - _direction_pin = UNDEFINED_PIN; + _direction_pin = UNDEFINED_PIN; #endif - is_reversable = (_direction_pin != UNDEFINED_PIN); + is_reversable = (_direction_pin != UNDEFINED_PIN); - _pwm_freq = spindle_pwm_freq->get(); - _pwm_precision = calc_pwm_precision(_pwm_freq); // detewrmine the best precision - _pwm_period = (1 << _pwm_precision); + _pwm_freq = spindle_pwm_freq->get(); + _pwm_precision = calc_pwm_precision(_pwm_freq); // detewrmine the best precision + _pwm_period = (1 << _pwm_precision); - if (spindle_pwm_min_value->get() > spindle_pwm_min_value->get()) - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Spindle min pwm is greater than max. Check $35 and $36"); + if (spindle_pwm_min_value->get() > spindle_pwm_min_value->get()) + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Spindle min pwm is greater than max. Check $35 and $36"); - // pre-caculate some PWM count values - _pwm_off_value = (_pwm_period * spindle_pwm_off_value->get() / 100.0); - _pwm_min_value = (_pwm_period * spindle_pwm_min_value->get() / 100.0); - _pwm_max_value = (_pwm_period * spindle_pwm_max_value->get() / 100.0); + // pre-caculate some PWM count values + _pwm_off_value = (_pwm_period * spindle_pwm_off_value->get() / 100.0); + _pwm_min_value = (_pwm_period * spindle_pwm_min_value->get() / 100.0); + _pwm_max_value = (_pwm_period * spindle_pwm_max_value->get() / 100.0); #ifdef ENABLE_PIECEWISE_LINEAR_SPINDLE - _min_rpm = RPM_MIN; - _max_rpm = RPM_MAX; - _piecewide_linear = true; + _min_rpm = RPM_MIN; + _max_rpm = RPM_MAX; + _piecewide_linear = true; #else - _min_rpm = rpm_min->get(); - _max_rpm = rpm_max->get(); - _piecewide_linear = false; + _min_rpm = rpm_min->get(); + _max_rpm = rpm_max->get(); + _piecewide_linear = false; #endif - // The pwm_gradient is the pwm duty cycle units per rpm - // _pwm_gradient = (_pwm_max_value - _pwm_min_value) / (_max_rpm - _min_rpm); + // The pwm_gradient is the pwm duty cycle units per rpm + // _pwm_gradient = (_pwm_max_value - _pwm_min_value) / (_max_rpm - _min_rpm); - _spindle_pwm_chan_num = 0; // Channel 0 is reserved for spindle use -} - -uint32_t PWMSpindle::set_rpm(uint32_t rpm) { - uint32_t pwm_value; - - if (_output_pin == UNDEFINED_PIN) - return rpm; - - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "set_rpm(%d)", rpm); - - // apply override - rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (uint8_t percent) - - // apply limits - if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm)) - rpm = _max_rpm; - else if (rpm != 0 && rpm <= _min_rpm) - rpm = _min_rpm; - - sys.spindle_speed = rpm; - - if (_piecewide_linear) { - //pwm_value = piecewise_linear_fit(rpm); TODO - pwm_value = 0; - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Linear fit not implemented yet."); - - } else { - if (rpm == 0) - pwm_value = _pwm_off_value; - else - pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value); + _spindle_pwm_chan_num = 0; // Channel 0 is reserved for spindle use } - set_output(pwm_value); + uint32_t PWMSpindle::set_rpm(uint32_t rpm) { + uint32_t pwm_value; - return 0; -} + if (_output_pin == UNDEFINED_PIN) + return rpm; -void PWMSpindle::set_state(uint8_t state, uint32_t rpm) { - if (sys.abort) - return; // Block during abort. + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "set_rpm(%d)", rpm); - if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm. - sys.spindle_speed = 0; - stop(); - if (use_delays && (_current_state != state)) { - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinDown Start "); - mc_dwell(spindle_delay_spindown->get()); - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinDown Done"); - } - } else { - set_spindle_dir_pin(state == SPINDLE_ENABLE_CW); - set_rpm(rpm); - set_enable_pin(state != SPINDLE_DISABLE); // must be done after setting rpm for enable features to work - if (use_delays && (_current_state != state)) { - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinUp Start %d", rpm); - mc_dwell(spindle_delay_spinup->get()); - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinUp Done"); + // apply override + rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (uint8_t percent) + + // apply limits + if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm)) + rpm = _max_rpm; + else if (rpm != 0 && rpm <= _min_rpm) + rpm = _min_rpm; + + sys.spindle_speed = rpm; + + if (_piecewide_linear) { + //pwm_value = piecewise_linear_fit(rpm); TODO + pwm_value = 0; + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Linear fit not implemented yet."); + + } else { + if (rpm == 0) + pwm_value = _pwm_off_value; + else + pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value); } + + set_output(pwm_value); + + return 0; } - _current_state = state; + void PWMSpindle::set_state(uint8_t state, uint32_t rpm) { + if (sys.abort) + return; // Block during abort. - sys.report_ovr_counter = 0; // Set to report change immediately -} + if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm. + sys.spindle_speed = 0; + stop(); + if (use_delays && (_current_state != state)) { + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinDown Start "); + mc_dwell(spindle_delay_spindown->get()); + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinDown Done"); + } + } else { + set_spindle_dir_pin(state == SPINDLE_ENABLE_CW); + set_rpm(rpm); + set_enable_pin(state != SPINDLE_DISABLE); // must be done after setting rpm for enable features to work + if (use_delays && (_current_state != state)) { + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinUp Start %d", rpm); + mc_dwell(spindle_delay_spinup->get()); + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinUp Done"); + } + } -uint8_t PWMSpindle::get_state() { - if (_current_pwm_duty == 0 || _output_pin == UNDEFINED_PIN) - return (SPINDLE_STATE_DISABLE); - if (_direction_pin != UNDEFINED_PIN) - return digitalRead(_direction_pin) ? SPINDLE_STATE_CW : SPINDLE_STATE_CCW; - return (SPINDLE_STATE_CW); -} + _current_state = state; -void PWMSpindle::stop() { - // inverts are delt with in methods - set_enable_pin(false); - set_output(_pwm_off_value); -} + sys.report_ovr_counter = 0; // Set to report change immediately + } -// prints the startup message of the spindle config -void PWMSpindle ::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, - MSG_LEVEL_INFO, - "PWM spindle Output:%s, Enbl:%s, Dir:%s, Freq:%dHz, Res:%dbits", - pinName(_output_pin).c_str(), - pinName(_enable_pin).c_str(), - pinName(_direction_pin).c_str(), - _pwm_freq, - _pwm_precision); -} + uint8_t PWMSpindle::get_state() { + if (_current_pwm_duty == 0 || _output_pin == UNDEFINED_PIN) + return (SPINDLE_STATE_DISABLE); + if (_direction_pin != UNDEFINED_PIN) + return digitalRead(_direction_pin) ? SPINDLE_STATE_CW : SPINDLE_STATE_CCW; + return (SPINDLE_STATE_CW); + } -void PWMSpindle::set_output(uint32_t duty) { - if (_output_pin == UNDEFINED_PIN) - return; + void PWMSpindle::stop() { + // inverts are delt with in methods + set_enable_pin(false); + set_output(_pwm_off_value); + } - // to prevent excessive calls to ledcWrite, make sure duty hass changed - if (duty == _current_pwm_duty) - return; + // prints the startup message of the spindle config + void PWMSpindle::config_message() { + grbl_msg_sendf(CLIENT_SERIAL, + MSG_LEVEL_INFO, + "PWM spindle Output:%s, Enbl:%s, Dir:%s, Freq:%dHz, Res:%dbits", + pinName(_output_pin).c_str(), + pinName(_enable_pin).c_str(), + pinName(_direction_pin).c_str(), + _pwm_freq, + _pwm_precision); + } - _current_pwm_duty = duty; + void PWMSpindle::set_output(uint32_t duty) { + if (_output_pin == UNDEFINED_PIN) + return; - if (_invert_pwm) - duty = (1 << _pwm_precision) - duty; + // to prevent excessive calls to ledcWrite, make sure duty hass changed + if (duty == _current_pwm_duty) + return; - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "set_output(%d)", duty); + _current_pwm_duty = duty; - ledcWrite(_spindle_pwm_chan_num, duty); -} + if (_invert_pwm) + duty = (1 << _pwm_precision) - duty; -void PWMSpindle::set_enable_pin(bool enable) { - if (_enable_pin == UNDEFINED_PIN) - return; + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "set_output(%d)", duty); - if (_off_with_zero_speed && sys.spindle_speed == 0) - enable = false; + ledcWrite(_spindle_pwm_chan_num, duty); + } + + void PWMSpindle::set_enable_pin(bool enable) { + if (_enable_pin == UNDEFINED_PIN) + return; + + if (_off_with_zero_speed && sys.spindle_speed == 0) + enable = false; #ifndef INVERT_SPINDLE_ENABLE_PIN - digitalWrite(_enable_pin, enable); + digitalWrite(_enable_pin, enable); #else - digitalWrite(_enable_pin, !enable); + digitalWrite(_enable_pin, !enable); #endif - digitalWrite(_enable_pin, enable); -} - -void PWMSpindle::set_spindle_dir_pin(bool Clockwise) { - digitalWrite(_direction_pin, Clockwise); -} - -/* - Calculate the highest precision of a PWM based on the frequency in bits - - 80,000,000 / freq = period - determine the highest precision where (1 << precision) < period -*/ -uint8_t PWMSpindle ::calc_pwm_precision(uint32_t freq) { - uint8_t precision = 0; - - // increase the precision (bits) until it exceeds allow by frequency the max or is 16 - while ((1 << precision) < (uint32_t)(80000000 / freq) && precision <= 16) - precision++; - - return precision - 1; + digitalWrite(_enable_pin, enable); + } + + void PWMSpindle::set_spindle_dir_pin(bool Clockwise) { digitalWrite(_direction_pin, Clockwise); } + + /* + Calculate the highest precision of a PWM based on the frequency in bits + + 80,000,000 / freq = period + determine the highest precision where (1 << precision) < period + */ + uint8_t PWMSpindle::calc_pwm_precision(uint32_t freq) { + uint8_t precision = 0; + + // increase the precision (bits) until it exceeds allow by frequency the max or is 16 + while ((1 << precision) < (uint32_t)(80000000 / freq) && precision <= 16) + precision++; + + return precision - 1; + } } diff --git a/Grbl_Esp32/src/Spindles/PWMSpindle.h b/Grbl_Esp32/src/Spindles/PWMSpindle.h new file mode 100644 index 00000000..effaa1ef --- /dev/null +++ b/Grbl_Esp32/src/Spindles/PWMSpindle.h @@ -0,0 +1,72 @@ +#pragma once + +/* + PWMSpindle.h + + This is a full featured TTL PWM spindle This does not include speed/power + compensation. Use the Laser class for that. + + Part of Grbl_ESP32 + 2020 - Bart Dring + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . + +*/ +#include "Spindle.h" + +namespace Spindles { + // This adds support for PWM + class PWMSpindle : public Spindle { + public: + PWMSpindle() = default; + + PWMSpindle(const PWMSpindle&) = delete; + PWMSpindle(PWMSpindle&&) = delete; + PWMSpindle& operator=(const PWMSpindle&) = delete; + PWMSpindle& operator=(PWMSpindle&&) = delete; + + void init() override; + virtual uint32_t set_rpm(uint32_t rpm) override; + void set_state(uint8_t state, uint32_t rpm) override; + uint8_t get_state() override; + void stop() override; + void config_message() override; + + virtual ~PWMSpindle() {} + + protected: + int32_t _current_pwm_duty; + uint32_t _min_rpm; + uint32_t _max_rpm; + uint32_t _pwm_off_value; + uint32_t _pwm_min_value; + uint32_t _pwm_max_value; + uint8_t _output_pin; + uint8_t _enable_pin; + uint8_t _direction_pin; + uint8_t _spindle_pwm_chan_num; + uint32_t _pwm_freq; + uint32_t _pwm_period; // how many counts in 1 period + uint8_t _pwm_precision; + bool _piecewide_linear; + bool _off_with_zero_speed; + bool _invert_pwm; + //uint32_t _pwm_gradient; // Precalulated value to speed up rpm to PWM conversions. + + virtual void set_spindle_dir_pin(bool Clockwise); + virtual void set_output(uint32_t duty); + virtual void set_enable_pin(bool enable_pin); + + void get_pins_and_settings(); + uint8_t calc_pwm_precision(uint32_t freq); + }; +} diff --git a/Grbl_Esp32/src/Spindles/RelaySpindle.cpp b/Grbl_Esp32/src/Spindles/RelaySpindle.cpp index bf287303..2ce0c5af 100644 --- a/Grbl_Esp32/src/Spindles/RelaySpindle.cpp +++ b/Grbl_Esp32/src/Spindles/RelaySpindle.cpp @@ -19,51 +19,54 @@ along with Grbl. If not, see . */ -#include "SpindleClass.h" +#include "RelaySpindle.h" // ========================= RelaySpindle ================================== -/* + +namespace Spindles { + /* This is a sub class of PWMSpindle but is a digital rather than PWM output */ -void RelaySpindle::init() { - get_pins_and_settings(); + void RelaySpindle::init() { + get_pins_and_settings(); - if (_output_pin == UNDEFINED_PIN) - return; + if (_output_pin == UNDEFINED_PIN) + return; - pinMode(_output_pin, OUTPUT); - pinMode(_enable_pin, OUTPUT); - pinMode(_direction_pin, OUTPUT); + pinMode(_output_pin, OUTPUT); + pinMode(_enable_pin, OUTPUT); + pinMode(_direction_pin, OUTPUT); - is_reversable = (_direction_pin != UNDEFINED_PIN); - use_delays = true; + is_reversable = (_direction_pin != UNDEFINED_PIN); + use_delays = true; - config_message(); -} + config_message(); + } -// prints the startup message of the spindle config -void RelaySpindle ::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, - MSG_LEVEL_INFO, - "Relay spindle Output:%s, Enbl:%s, Dir:%s", - pinName(_output_pin).c_str(), - pinName(_enable_pin).c_str(), - pinName(_direction_pin).c_str()); -} + // prints the startup message of the spindle config + void RelaySpindle ::config_message() { + grbl_msg_sendf(CLIENT_SERIAL, + MSG_LEVEL_INFO, + "Relay spindle Output:%s, Enbl:%s, Dir:%s", + pinName(_output_pin).c_str(), + pinName(_enable_pin).c_str(), + pinName(_direction_pin).c_str()); + } + + uint32_t RelaySpindle::set_rpm(uint32_t rpm) { + if (_output_pin == UNDEFINED_PIN) + return rpm; + + sys.spindle_speed = rpm; + set_output(rpm != 0); -uint32_t RelaySpindle::set_rpm(uint32_t rpm) { - if (_output_pin == UNDEFINED_PIN) return rpm; + } - sys.spindle_speed = rpm; - set_output(rpm != 0); - - return rpm; -} - -void RelaySpindle::set_output(uint32_t duty) { + void RelaySpindle::set_output(uint32_t duty) { #ifdef INVERT_SPINDLE_PWM - duty = (duty == 0); // flip duty + duty = (duty == 0); // flip duty #endif - digitalWrite(_output_pin, duty > 0); // anything greater + digitalWrite(_output_pin, duty > 0); // anything greater + } } diff --git a/Grbl_Esp32/src/Spindles/RelaySpindle.h b/Grbl_Esp32/src/Spindles/RelaySpindle.h new file mode 100644 index 00000000..c7d37bd1 --- /dev/null +++ b/Grbl_Esp32/src/Spindles/RelaySpindle.h @@ -0,0 +1,46 @@ +#pragma once + +/* + RelaySpindle.h + + This is used for a basic on/off spindle All S Values above 0 + will turn the spindle on. + + Part of Grbl_ESP32 + 2020 - Bart Dring + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . + +*/ +#include "PWMSpindle.h" + +namespace Spindles { + // This is for an on/off spindle all RPMs above 0 are on + class RelaySpindle : public PWMSpindle { + public: + RelaySpindle() = default; + + RelaySpindle(const RelaySpindle&) = delete; + RelaySpindle(RelaySpindle&&) = delete; + RelaySpindle& operator=(const RelaySpindle&) = delete; + RelaySpindle& operator=(RelaySpindle&&) = delete; + + void init() override; + void config_message() override; + uint32_t set_rpm(uint32_t rpm) override; + + virtual ~RelaySpindle() {} + + protected: + void set_output(uint32_t duty); + }; +} diff --git a/Grbl_Esp32/src/Spindles/Spindle.cpp b/Grbl_Esp32/src/Spindles/Spindle.cpp new file mode 100644 index 00000000..132cc705 --- /dev/null +++ b/Grbl_Esp32/src/Spindles/Spindle.cpp @@ -0,0 +1,81 @@ +/* + SpindleClass.cpp + + A Base class for spindles and spinsle like things such as lasers + + Part of Grbl_ESP32 + + 2020 - Bart Dring + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . + + TODO + Add Spindle spin up/down delays + + Get rid of dependance on machine definition #defines + SPINDLE_OUTPUT_PIN + SPINDLE_ENABLE_PIN + SPINDLE_DIR_PIN + +*/ +#include "Spindle.h" + +#include "NullSpindle.h" +#include "PWMSpindle.h" +#include "RelaySpindle.h" +#include "Laser.h" +#include "DacSpindle.h" +#include "HuanyangSpindle.h" +#include "BESCSpindle.h" +#include "10vSpindle.h" + +namespace Spindles { + // An instance of each type of spindle is created here. + // This allows the spindle to be dynamicly switched + NullSpindle null_spindle; + PWMSpindle pwm_spindle; + RelaySpindle relay_spindle; + Laser laser; + DacSpindle dac_spindle; + HuanyangSpindle huanyang_spindle; + BESCSpindle besc_spindle; + _10vSpindle _10v_spindle; + + void Spindle::spindle_select() { + switch (spindle_type->get()) { + case SPINDLE_TYPE_PWM: spindle = &pwm_spindle; break; + case SPINDLE_TYPE_RELAY: spindle = &relay_spindle; break; + case SPINDLE_TYPE_LASER: spindle = &laser; break; + case SPINDLE_TYPE_DAC: spindle = &dac_spindle; break; + case SPINDLE_TYPE_HUANYANG: spindle = &huanyang_spindle; break; + case SPINDLE_TYPE_BESC: spindle = &besc_spindle; break; + case SPINDLE_TYPE_10V: spindle = &_10v_spindle; break; + case SPINDLE_TYPE_NONE: + default: spindle = &null_spindle; break; + } + + spindle->init(); + } + + // ========================= Spindle ================================== + + bool Spindle::isRateAdjusted() { + return false; // default for basic spindle is false + } + + void Spindle::spindle_sync(uint8_t state, uint32_t rpm) { + if (sys.state == STATE_CHECK_MODE) + return; + protocol_buffer_synchronize(); // Empty planner buffer to ensure spindle is set when programmed. + set_state(state, rpm); + } +} diff --git a/Grbl_Esp32/src/Spindles/Spindle.h b/Grbl_Esp32/src/Spindles/Spindle.h new file mode 100644 index 00000000..ef57643d --- /dev/null +++ b/Grbl_Esp32/src/Spindles/Spindle.h @@ -0,0 +1,80 @@ +#pragma once + +/* + Spindle.h + + Header file for a Spindle Class + See SpindleClass.cpp for more details + + Part of Grbl_ESP32 + + 2020 - Bart Dring This file was modified for use on the ESP32 + CPU. Do not use this with Grbl for atMega328P + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . + + See SpindleClass.cpp for more info and references + +*/ + +#define SPINDLE_STATE_DISABLE 0 // Must be zero. +#define SPINDLE_STATE_CW bit(0) +#define SPINDLE_STATE_CCW bit(1) + +#define SPINDLE_TYPE_NONE 0 +#define SPINDLE_TYPE_PWM 1 +#define SPINDLE_TYPE_RELAY 2 +#define SPINDLE_TYPE_LASER 3 +#define SPINDLE_TYPE_DAC 4 +#define SPINDLE_TYPE_HUANYANG 5 +#define SPINDLE_TYPE_BESC 6 +#define SPINDLE_TYPE_10V 7 + +#include "../grbl.h" +#include +#include + +// =============== No floats! =========================== +// ================ NO FLOATS! ========================== + +namespace Spindles { + // This is the base class. Do not use this as your spindle + class Spindle { + public: + Spindle() = default; + + Spindle(const Spindle&) = delete; + Spindle(Spindle&&) = delete; + Spindle& operator=(const Spindle&) = delete; + Spindle& operator=(Spindle&&) = delete; + + virtual void init() = 0; // not in constructor because this also gets called when $$ settings change + virtual uint32_t set_rpm(uint32_t rpm) = 0; + virtual void set_state(uint8_t state, uint32_t rpm) = 0; + virtual uint8_t get_state() = 0; + virtual void stop() = 0; + virtual void config_message() = 0; + virtual bool isRateAdjusted(); + virtual void spindle_sync(uint8_t state, uint32_t rpm); + + virtual ~Spindle() {} + + bool is_reversable; + bool use_delays; // will SpinUp and SpinDown delays be used. + uint8_t _current_state; + + static void spindle_select(); + }; + +} + +extern Spindles::Spindle* spindle; diff --git a/Grbl_Esp32/src/Spindles/SpindleClass.cpp b/Grbl_Esp32/src/Spindles/SpindleClass.cpp deleted file mode 100644 index a6786a5d..00000000 --- a/Grbl_Esp32/src/Spindles/SpindleClass.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - SpindleClass.cpp - - A Base class for spindles and spinsle like things such as lasers - - Part of Grbl_ESP32 - - 2020 - Bart Dring - - Grbl is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - Grbl is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Grbl. If not, see . - - TODO - Add Spindle spin up/down delays - - Get rid of dependance on machine definition #defines - SPINDLE_OUTPUT_PIN - SPINDLE_ENABLE_PIN - SPINDLE_DIR_PIN - -*/ -#include "SpindleClass.h" - -// An instance of each type of spindle is created here. -// This allows the spindle to be dynamicly switched -NullSpindle null_spindle; -PWMSpindle pwm_spindle; -RelaySpindle relay_spindle; -Laser laser; -DacSpindle dac_spindle; -HuanyangSpindle huanyang_spindle; -BESCSpindle besc_spindle; -_10vSpindle _10v_spindle; - -void spindle_select() { - switch (spindle_type->get()) { - case SPINDLE_TYPE_PWM: spindle = &pwm_spindle; break; - case SPINDLE_TYPE_RELAY: spindle = &relay_spindle; break; - case SPINDLE_TYPE_LASER: spindle = &laser; break; - case SPINDLE_TYPE_DAC: spindle = &dac_spindle; break; - case SPINDLE_TYPE_HUANYANG: spindle = &huanyang_spindle; break; - case SPINDLE_TYPE_BESC: spindle = &besc_spindle; break; - case SPINDLE_TYPE_10V: spindle = &_10v_spindle; break; - case SPINDLE_TYPE_NONE: - default: spindle = &null_spindle; break; - } - - spindle->init(); -} - -// ========================= Spindle ================================== - -bool Spindle::isRateAdjusted() { - return false; // default for basic spindle is false -} - -void Spindle ::spindle_sync(uint8_t state, uint32_t rpm) { - if (sys.state == STATE_CHECK_MODE) - return; - protocol_buffer_synchronize(); // Empty planner buffer to ensure spindle is set when programmed. - set_state(state, rpm); -} diff --git a/Grbl_Esp32/src/Spindles/SpindleClass.h b/Grbl_Esp32/src/Spindles/SpindleClass.h deleted file mode 100644 index 5560c26f..00000000 --- a/Grbl_Esp32/src/Spindles/SpindleClass.h +++ /dev/null @@ -1,217 +0,0 @@ -#pragma once - -/* - SpindleClass.h - - Header file for a Spindle Class - See SpindleClass.cpp for more details - - Part of Grbl_ESP32 - - 2020 - Bart Dring This file was modified for use on the ESP32 - CPU. Do not use this with Grbl for atMega328P - - Grbl is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - Grbl is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Grbl. If not, see . - - See SpindleClass.cpp for more info and references - -*/ - -#define SPINDLE_STATE_DISABLE 0 // Must be zero. -#define SPINDLE_STATE_CW bit(0) -#define SPINDLE_STATE_CCW bit(1) - -#define SPINDLE_TYPE_NONE 0 -#define SPINDLE_TYPE_PWM 1 -#define SPINDLE_TYPE_RELAY 2 -#define SPINDLE_TYPE_LASER 3 -#define SPINDLE_TYPE_DAC 4 -#define SPINDLE_TYPE_HUANYANG 5 -#define SPINDLE_TYPE_BESC 6 -#define SPINDLE_TYPE_10V 7 - -#include "../grbl.h" -#include -#include "driver/uart.h" - -// =============== No floats! =========================== -// ================ NO FLOATS! ========================== - -// This is the base class. Do not use this as your spindle -class Spindle { -public: - virtual void init(); // not in constructor because this also gets called when $$ settings change - virtual uint32_t set_rpm(uint32_t rpm); - virtual void set_state(uint8_t state, uint32_t rpm); - virtual uint8_t get_state(); - virtual void stop(); - virtual void config_message(); - virtual bool isRateAdjusted(); - virtual void spindle_sync(uint8_t state, uint32_t rpm); - - bool is_reversable; - bool use_delays; // will SpinUp and SpinDown delays be used. - uint8_t _current_state; -}; - -// This is a dummy spindle that has no I/O. -// It is used to ignore spindle commands when no spinde is desired -class NullSpindle : public Spindle { -public: - void init(); - uint32_t set_rpm(uint32_t rpm); - void set_state(uint8_t state, uint32_t rpm); - uint8_t get_state(); - void stop(); - void config_message(); -}; - -// This adds support for PWM -class PWMSpindle : public Spindle { -public: - void init(); - virtual uint32_t set_rpm(uint32_t rpm); - void set_state(uint8_t state, uint32_t rpm); - uint8_t get_state(); - void stop(); - void config_message(); - -private: - void set_spindle_dir_pin(bool Clockwise); - -protected: - int32_t _current_pwm_duty; - uint32_t _min_rpm; - uint32_t _max_rpm; - uint32_t _pwm_off_value; - uint32_t _pwm_min_value; - uint32_t _pwm_max_value; - uint8_t _output_pin; - uint8_t _enable_pin; - uint8_t _direction_pin; - uint8_t _spindle_pwm_chan_num; - uint32_t _pwm_freq; - uint32_t _pwm_period; // how many counts in 1 period - uint8_t _pwm_precision; - bool _piecewide_linear; - bool _off_with_zero_speed; - bool _invert_pwm; - //uint32_t _pwm_gradient; // Precalulated value to speed up rpm to PWM conversions. - - virtual void set_output(uint32_t duty); - void set_enable_pin(bool enable_pin); - void get_pins_and_settings(); - uint8_t calc_pwm_precision(uint32_t freq); -}; - -// This is for an on/off spindle all RPMs above 0 are on -class RelaySpindle : public PWMSpindle { -public: - void init(); - void config_message(); - uint32_t set_rpm(uint32_t rpm); - -protected: - void set_output(uint32_t duty); -}; - -// this is the same as a PWM spindle but the M4 compensation is supported. -class Laser : public PWMSpindle { -public: - bool isRateAdjusted(); - void config_message(); -}; - -// This uses one of the (2) DAC pins on ESP32 to output a voltage -class DacSpindle : public PWMSpindle { -public: - void init(); - void config_message(); - uint32_t set_rpm(uint32_t rpm); - -private: - bool _gpio_ok; // DAC is on a valid pin -protected: - void set_output(uint32_t duty); // sets DAC instead of PWM -}; - -class HuanyangSpindle : public Spindle { -private: - uint16_t ModRTU_CRC(char* buf, int len); - - bool set_mode(uint8_t mode, bool critical); - - bool get_pins_and_settings(); - - uint32_t _current_rpm; - uint8_t _txd_pin; - uint8_t _rxd_pin; - uint8_t _rts_pin; - uint8_t _state; - bool _task_running; - -public: - HuanyangSpindle() { _task_running = false; } - void init(); - void config_message(); - void set_state(uint8_t state, uint32_t rpm); - uint8_t get_state(); - uint32_t set_rpm(uint32_t rpm); - void stop(); - static void read_value(uint8_t reg); - static void add_ModRTU_CRC(char* buf, int full_msg_len); - -protected: - uint32_t _min_rpm; - uint32_t _max_rpm; -}; - -class BESCSpindle : public PWMSpindle { -public: - void init(); - void config_message(); - uint32_t set_rpm(uint32_t rpm); -}; - -class _10vSpindle : public PWMSpindle { -public: - void init(); - void config_message(); - uint32_t set_rpm(uint32_t rpm); - uint8_t _forward_pin; - uint8_t _reverse_pin; - - //void set_state(uint8_t state, uint32_t rpm); - - uint8_t get_state(); - void stop(); - -protected: - void set_enable_pin(bool enable_pin); - void set_spindle_dir_pin(bool Clockwise); -}; - -extern Spindle* spindle; - -extern NullSpindle null_spindle; -extern PWMSpindle pwm_spindle; -extern RelaySpindle relay_spindle; -extern Laser laser; -extern DacSpindle dac_spindle; -extern HuanyangSpindle huanyang_spindle; -extern BESCSpindle besc_spindle; -extern _10vSpindle _10v_spindle; - -void spindle_select(); - -// in HuanyangSpindle.cpp -void vfd_cmd_task(void* pvParameters); diff --git a/Grbl_Esp32/src/grbl.h b/Grbl_Esp32/src/grbl.h index 1a2770cd..9f8d18ee 100644 --- a/Grbl_Esp32/src/grbl.h +++ b/Grbl_Esp32/src/grbl.h @@ -56,7 +56,7 @@ #include "report.h" #include "serial.h" #include "Pins.h" -#include "Spindles/SpindleClass.h" +#include "Spindles/Spindle.h" #include "Motors/Motors.h" #include "stepper.h" #include "jog.h"