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"